activemerchant 1.18.1 → 1.20.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 +5 -0
- data/CHANGELOG +15 -0
- data/CONTRIBUTORS +4 -0
- data/lib/active_merchant.rb +1 -0
- data/lib/active_merchant/billing/credit_card.rb +1 -1
- data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +5 -1
- data/lib/active_merchant/billing/gateways/braintree_blue.rb +6 -2
- data/lib/active_merchant/billing/gateways/elavon.rb +2 -1
- data/lib/active_merchant/billing/gateways/exact.rb +5 -0
- data/lib/active_merchant/billing/gateways/moneris.rb +4 -0
- data/lib/active_merchant/billing/gateways/ogone.rb +94 -56
- data/lib/active_merchant/billing/gateways/orbital.rb +34 -26
- data/lib/active_merchant/billing/gateways/pay_junction.rb +6 -1
- data/lib/active_merchant/billing/gateways/samurai.rb +120 -0
- data/lib/active_merchant/billing/gateways/skip_jack.rb +6 -1
- data/lib/active_merchant/billing/gateways/usa_epay.rb +13 -184
- data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +1496 -0
- data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +194 -0
- data/lib/active_merchant/billing/integrations/dwolla.rb +2 -2
- data/lib/active_merchant/billing/integrations/dwolla/helper.rb +7 -4
- data/lib/active_merchant/billing/integrations/dwolla/notification.rb +5 -0
- data/lib/active_merchant/billing/integrations/helper.rb +6 -1
- data/lib/active_merchant/billing/integrations/payflow_link/helper.rb +46 -4
- data/lib/active_merchant/billing/integrations/two_checkout.rb +1 -2
- data/lib/active_merchant/version.rb +1 -1
- metadata +66 -40
- metadata.gz.sig +0 -0
@@ -202,7 +202,7 @@ module ActiveMerchant #:nodoc:
|
|
202
202
|
|
203
203
|
# Return money to a card that was previously billed.
|
204
204
|
# _authorization_ should be the transaction id of the transaction we are returning.
|
205
|
-
def
|
205
|
+
def refund(money, authorization, options = {})
|
206
206
|
parameters = {
|
207
207
|
:transaction_amount => amount(money),
|
208
208
|
:transaction_id => authorization
|
@@ -211,6 +211,11 @@ module ActiveMerchant #:nodoc:
|
|
211
211
|
commit('CREDIT', parameters)
|
212
212
|
end
|
213
213
|
|
214
|
+
def credit(money, authorization, options = {})
|
215
|
+
deprecated CREDIT_DEPRECATION_MESSAGE
|
216
|
+
refund(money, authorization, options)
|
217
|
+
end
|
218
|
+
|
214
219
|
# Cancel a transaction that has been charged but has not yet made it
|
215
220
|
# through the batch process.
|
216
221
|
def void(authorization, options = {})
|
@@ -0,0 +1,120 @@
|
|
1
|
+
module ActiveMerchant #:nodoc:
|
2
|
+
module Billing #:nodoc:
|
3
|
+
class SamuraiGateway < Gateway
|
4
|
+
|
5
|
+
self.homepage_url = 'https://samurai.feefighters.com'
|
6
|
+
self.display_name = 'Samurai'
|
7
|
+
self.supported_countries = ['US']
|
8
|
+
self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :diners_club]
|
9
|
+
self.default_currency = 'USD'
|
10
|
+
self.money_format = :dollars
|
11
|
+
|
12
|
+
def initialize(options = {})
|
13
|
+
begin
|
14
|
+
require 'samurai'
|
15
|
+
rescue LoadError
|
16
|
+
raise "Could not load the samurai gem (>= 0.2.25). Use `gem install samurai` to install it."
|
17
|
+
end
|
18
|
+
|
19
|
+
requires!(options, :login, :password, :processor_token)
|
20
|
+
@options = options
|
21
|
+
Samurai.options = {
|
22
|
+
:merchant_key => options[:login],
|
23
|
+
:merchant_password => options[:password],
|
24
|
+
:processor_token => options[:processor_token]
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
def test?
|
29
|
+
@options[:test] || super
|
30
|
+
end
|
31
|
+
|
32
|
+
def authorize(money, credit_card_or_vault_id, options = {})
|
33
|
+
token = payment_method_token(credit_card_or_vault_id, options)
|
34
|
+
return token if token.is_a?(Response)
|
35
|
+
|
36
|
+
authorize = Samurai::Processor.authorize(token, amount(money), processor_options(options))
|
37
|
+
handle_result(authorize)
|
38
|
+
end
|
39
|
+
|
40
|
+
def purchase(money, credit_card_or_vault_id, options = {})
|
41
|
+
token = payment_method_token(credit_card_or_vault_id, options)
|
42
|
+
return token if token.is_a?(Response)
|
43
|
+
|
44
|
+
purchase = Samurai::Processor.purchase(token, amount(money), processor_options(options))
|
45
|
+
handle_result(purchase)
|
46
|
+
end
|
47
|
+
|
48
|
+
def capture(money, authorization_id, options = {})
|
49
|
+
transaction = Samurai::Transaction.find(authorization_id)
|
50
|
+
handle_result(transaction.capture(amount(money)))
|
51
|
+
end
|
52
|
+
|
53
|
+
def refund(money, transaction_id, options = {})
|
54
|
+
transaction = Samurai::Transaction.find(transaction_id)
|
55
|
+
handle_result(transaction.credit(amount(money)))
|
56
|
+
end
|
57
|
+
|
58
|
+
def void(transaction_id, options = {})
|
59
|
+
transaction = Samurai::Transaction.find(transaction_id)
|
60
|
+
handle_result(transaction.void)
|
61
|
+
end
|
62
|
+
|
63
|
+
def store(creditcard, options = {})
|
64
|
+
address = options[:billing_address] || options[:address] || {}
|
65
|
+
|
66
|
+
result = Samurai::PaymentMethod.create({
|
67
|
+
:card_number => creditcard.number,
|
68
|
+
:expiry_month => creditcard.month.to_s.rjust(2, "0"),
|
69
|
+
:expiry_year => creditcard.year.to_s,
|
70
|
+
:cvv => creditcard.verification_value,
|
71
|
+
:first_name => creditcard.first_name,
|
72
|
+
:last_name => creditcard.last_name,
|
73
|
+
:address_1 => address[:address1],
|
74
|
+
:address_2 => address[:address2],
|
75
|
+
:city => address[:city],
|
76
|
+
:zip => address[:zip],
|
77
|
+
:sandbox => test?
|
78
|
+
})
|
79
|
+
|
80
|
+
Response.new(result.is_sensitive_data_valid,
|
81
|
+
message_from_result(result),
|
82
|
+
{ :payment_method_token => result.is_sensitive_data_valid && result.payment_method_token })
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def payment_method_token(credit_card_or_vault_id, options)
|
88
|
+
return credit_card_or_vault_id if credit_card_or_vault_id.is_a?(String)
|
89
|
+
store_result = store(credit_card_or_vault_id, options)
|
90
|
+
store_result.success? ? store_result.params["payment_method_token"] : store_result
|
91
|
+
end
|
92
|
+
|
93
|
+
def handle_result(result)
|
94
|
+
response_params, response_options = {}, {}
|
95
|
+
if result.success?
|
96
|
+
response_options[:test] = test?
|
97
|
+
response_options[:authorization] = result.reference_id
|
98
|
+
response_params[:reference_id] = result.reference_id
|
99
|
+
response_params[:transaction_token] = result.transaction_token
|
100
|
+
response_params[:payment_method_token] = result.payment_method.payment_method_token
|
101
|
+
end
|
102
|
+
|
103
|
+
response_options[:avs_result] = { :code => result.processor_response && result.processor_response.avs_result_code }
|
104
|
+
response_options[:cvv_result] = result.processor_response && result.processor_response.cvv_result_code
|
105
|
+
|
106
|
+
message = message_from_result(result)
|
107
|
+
Response.new(result.success?, message, response_params, response_options)
|
108
|
+
end
|
109
|
+
|
110
|
+
def message_from_result(result)
|
111
|
+
return "OK" if result.success?
|
112
|
+
result.errors.map {|_, messages| messages }.join(" ")
|
113
|
+
end
|
114
|
+
|
115
|
+
def processor_options(options)
|
116
|
+
options.slice(:billing_reference, :customer_reference, :custom, :descriptor)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -236,7 +236,7 @@ module ActiveMerchant #:nodoc:
|
|
236
236
|
commit(:change_status, nil, post)
|
237
237
|
end
|
238
238
|
|
239
|
-
def
|
239
|
+
def refund(money, identification, options = {})
|
240
240
|
post = {}
|
241
241
|
add_status_action(post, 'CREDIT')
|
242
242
|
add_forced_settlement(post, options)
|
@@ -244,6 +244,11 @@ module ActiveMerchant #:nodoc:
|
|
244
244
|
commit(:change_status, money, post)
|
245
245
|
end
|
246
246
|
|
247
|
+
def credit(money, identification, options = {})
|
248
|
+
deprecated CREDIT_DEPRECATION_MESSAGE
|
249
|
+
refund(money, identification, options)
|
250
|
+
end
|
251
|
+
|
247
252
|
def status(order_id)
|
248
253
|
commit(:get_status, nil, :szOrderNumber => order_id)
|
249
254
|
end
|
@@ -1,194 +1,23 @@
|
|
1
1
|
module ActiveMerchant #:nodoc:
|
2
2
|
module Billing #:nodoc:
|
3
|
-
|
3
|
+
##
|
4
|
+
# Delegates to the appropriate gateway, either the Transaction or Advanced
|
5
|
+
# depending on options passed to new.
|
6
|
+
#
|
4
7
|
class UsaEpayGateway < Gateway
|
5
|
-
URL = 'https://www.usaepay.com/gate.php'
|
6
|
-
|
7
|
-
self.supported_cardtypes = [:visa, :master, :american_express]
|
8
|
-
self.supported_countries = ['US']
|
9
|
-
self.homepage_url = 'http://www.usaepay.com/'
|
10
|
-
self.display_name = 'USA ePay'
|
11
8
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
@options = options
|
21
|
-
super
|
22
|
-
end
|
23
|
-
|
24
|
-
def authorize(money, credit_card, options = {})
|
25
|
-
post = {}
|
26
|
-
|
27
|
-
add_amount(post, money)
|
28
|
-
add_invoice(post, options)
|
29
|
-
add_credit_card(post, credit_card)
|
30
|
-
add_address(post, credit_card, options)
|
31
|
-
add_customer_data(post, options)
|
32
|
-
|
33
|
-
commit(:authorization, post)
|
34
|
-
end
|
35
|
-
|
36
|
-
def purchase(money, credit_card, options = {})
|
37
|
-
post = {}
|
38
|
-
|
39
|
-
add_amount(post, money)
|
40
|
-
add_invoice(post, options)
|
41
|
-
add_credit_card(post, credit_card)
|
42
|
-
add_address(post, credit_card, options)
|
43
|
-
add_customer_data(post, options)
|
44
|
-
|
45
|
-
commit(:purchase, post)
|
46
|
-
end
|
47
|
-
|
48
|
-
def capture(money, authorization, options = {})
|
49
|
-
post = {
|
50
|
-
:refNum => authorization
|
51
|
-
}
|
52
|
-
|
53
|
-
add_amount(post, money)
|
54
|
-
commit(:capture, post)
|
55
|
-
end
|
56
|
-
|
57
|
-
private
|
58
|
-
|
59
|
-
def add_amount(post, money)
|
60
|
-
post[:amount] = amount(money)
|
61
|
-
end
|
62
|
-
|
63
|
-
def expdate(credit_card)
|
64
|
-
year = format(credit_card.year, :two_digits)
|
65
|
-
month = format(credit_card.month, :two_digits)
|
66
|
-
|
67
|
-
"#{month}#{year}"
|
68
|
-
end
|
69
|
-
|
70
|
-
def add_customer_data(post, options)
|
71
|
-
address = options[:billing_address] || options[:address] || {}
|
72
|
-
post[:street] = address[:address1]
|
73
|
-
post[:zip] = address[:zip]
|
74
|
-
|
75
|
-
if options.has_key? :email
|
76
|
-
post[:custemail] = options[:email]
|
77
|
-
post[:custreceipt] = 'No'
|
78
|
-
end
|
79
|
-
|
80
|
-
if options.has_key? :customer
|
81
|
-
post[:custid] = options[:customer]
|
82
|
-
end
|
83
|
-
|
84
|
-
if options.has_key? :ip
|
85
|
-
post[:ip] = options[:ip]
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
def add_address(post, credit_card, options)
|
90
|
-
billing_address = options[:billing_address] || options[:address]
|
91
|
-
|
92
|
-
add_address_for_type(:billing, post, credit_card, billing_address) if billing_address
|
93
|
-
add_address_for_type(:shipping, post, credit_card, options[:shipping_address]) if options[:shipping_address]
|
94
|
-
end
|
95
|
-
|
96
|
-
def add_address_for_type(type, post, credit_card, address)
|
97
|
-
prefix = address_key_prefix(type)
|
98
|
-
|
99
|
-
post[address_key(prefix, 'fname')] = credit_card.first_name
|
100
|
-
post[address_key(prefix, 'lname')] = credit_card.last_name
|
101
|
-
post[address_key(prefix, 'company')] = address[:company] unless address[:company].blank?
|
102
|
-
post[address_key(prefix, 'street')] = address[:address1] unless address[:address1].blank?
|
103
|
-
post[address_key(prefix, 'street2')] = address[:address2] unless address[:address2].blank?
|
104
|
-
post[address_key(prefix, 'city')] = address[:city] unless address[:city].blank?
|
105
|
-
post[address_key(prefix, 'state')] = address[:state] unless address[:state].blank?
|
106
|
-
post[address_key(prefix, 'zip')] = address[:zip] unless address[:zip].blank?
|
107
|
-
post[address_key(prefix, 'country')] = address[:country] unless address[:country].blank?
|
108
|
-
post[address_key(prefix, 'phone')] = address[:phone] unless address[:phone].blank?
|
109
|
-
end
|
110
|
-
|
111
|
-
def address_key_prefix(type)
|
112
|
-
case type
|
113
|
-
when :shipping then 'ship'
|
114
|
-
when :billing then 'bill'
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
def address_key(prefix, key)
|
119
|
-
"#{prefix}#{key}".to_sym
|
120
|
-
end
|
121
|
-
|
122
|
-
def add_invoice(post, options)
|
123
|
-
post[:invoice] = options[:order_id]
|
124
|
-
end
|
125
|
-
|
126
|
-
def add_credit_card(post, credit_card)
|
127
|
-
post[:card] = credit_card.number
|
128
|
-
post[:cvv2] = credit_card.verification_value if credit_card.verification_value?
|
129
|
-
post[:expir] = expdate(credit_card)
|
130
|
-
post[:name] = credit_card.name
|
131
|
-
end
|
132
|
-
|
133
|
-
def parse(body)
|
134
|
-
fields = {}
|
135
|
-
for line in body.split('&')
|
136
|
-
key, value = *line.scan( %r{^(\w+)\=(.*)$} ).flatten
|
137
|
-
fields[key] = CGI.unescape(value.to_s)
|
138
|
-
end
|
139
|
-
|
140
|
-
{
|
141
|
-
:status => fields['UMstatus'],
|
142
|
-
:auth_code => fields['UMauthCode'],
|
143
|
-
:ref_num => fields['UMrefNum'],
|
144
|
-
:batch => fields['UMbatch'],
|
145
|
-
:avs_result => fields['UMavsResult'],
|
146
|
-
:avs_result_code => fields['UMavsResultCode'],
|
147
|
-
:cvv2_result => fields['UMcvv2Result'],
|
148
|
-
:cvv2_result_code => fields['UMcvv2ResultCode'],
|
149
|
-
:vpas_result_code => fields['UMvpasResultCode'],
|
150
|
-
:result => fields['UMresult'],
|
151
|
-
:error => fields['UMerror'],
|
152
|
-
:error_code => fields['UMerrorcode'],
|
153
|
-
:acs_url => fields['UMacsurl'],
|
154
|
-
:payload => fields['UMpayload']
|
155
|
-
}.delete_if{|k, v| v.nil?}
|
156
|
-
end
|
157
|
-
|
158
|
-
|
159
|
-
def commit(action, parameters)
|
160
|
-
response = parse( ssl_post(URL, post_data(action, parameters)) )
|
161
|
-
|
162
|
-
Response.new(response[:status] == 'Approved', message_from(response), response,
|
163
|
-
:test => @options[:test] || test?,
|
164
|
-
:authorization => response[:ref_num],
|
165
|
-
:cvv_result => response[:cvv2_result_code],
|
166
|
-
:avs_result => {
|
167
|
-
:street_match => response[:avs_result_code].to_s[0,1],
|
168
|
-
:postal_match => response[:avs_result_code].to_s[1,1],
|
169
|
-
:code => response[:avs_result_code].to_s[2,1]
|
170
|
-
}
|
171
|
-
)
|
172
|
-
end
|
173
|
-
|
174
|
-
def message_from(response)
|
175
|
-
if response[:status] == "Approved"
|
176
|
-
return 'Success'
|
9
|
+
##
|
10
|
+
# Creates an instance of UsaEpayTransactionGateway by default, but if
|
11
|
+
# :software id or :live_url are passed in the options hash it will
|
12
|
+
# create an instance of UsaEpayAdvancedGateway.
|
13
|
+
#
|
14
|
+
def self.new(options={})
|
15
|
+
unless options.has_key?(:software_id) || options.has_key?(:live_url)
|
16
|
+
UsaEpayTransactionGateway.new(options)
|
177
17
|
else
|
178
|
-
|
179
|
-
return response[:error]
|
18
|
+
UsaEpayAdvancedGateway.new(options)
|
180
19
|
end
|
181
20
|
end
|
182
|
-
|
183
|
-
def post_data(action, parameters = {})
|
184
|
-
parameters[:command] = TRANSACTIONS[action]
|
185
|
-
parameters[:key] = @options[:login]
|
186
|
-
parameters[:software] = 'Active Merchant'
|
187
|
-
parameters[:testmode] = @options[:test] ? 1 : 0
|
188
|
-
|
189
|
-
parameters.collect { |key, value| "UM#{key}=#{CGI.escape(value.to_s)}" }.join("&")
|
190
|
-
end
|
191
21
|
end
|
192
22
|
end
|
193
23
|
end
|
194
|
-
|
@@ -0,0 +1,1496 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
require 'digest'
|
3
|
+
|
4
|
+
module ActiveMerchant #:nodoc:
|
5
|
+
module Billing #:nodoc:
|
6
|
+
# ==== USA ePay Advanced SOAP Interface
|
7
|
+
#
|
8
|
+
# This class encapuslates USA ePay's Advanced SOAP Interface. The Advanced Soap Interface allows
|
9
|
+
# standard transactions, storing customer information, and recurring billing. Storing sensitive
|
10
|
+
# information on USA ePay's servers can help with PCI DSS compliance, since customer and card data
|
11
|
+
# do not need to be stored locally.
|
12
|
+
#
|
13
|
+
# Make sure you have enabled this functionality for your account with USA ePay.
|
14
|
+
#
|
15
|
+
# Information about the Advanced SOAP interface is available on the {USA ePay wiki}[http://wiki.usaepay.com/developer/soap].
|
16
|
+
#
|
17
|
+
# ==== Login, Password, and Software ID
|
18
|
+
#
|
19
|
+
# Please follow all of USA ePay's directions for acquiring all accounts and settings.
|
20
|
+
#
|
21
|
+
# The value used for <tt>:login</tt> is the Key value found in the Merchant Console under Settings > Source
|
22
|
+
# Key. You will have to add this key in the USA ePay Merchant Console.
|
23
|
+
#
|
24
|
+
# The value used for <tt>:password</tt> is the pin value also found and assigned in the Merchant Console under
|
25
|
+
# Settings > Source Key. The pin is required to use all but basic transactions in the SOAP interface.
|
26
|
+
# You will have to add the pin to your source key, as it defaults to none.
|
27
|
+
#
|
28
|
+
# The value used for the <tt>:software_id</tt> is found in the Developer's Login under the Developers Center
|
29
|
+
# in your WSDL. It is the 8 character value in <soap:address> tag. A masked example:
|
30
|
+
# <soap:address location="https://www.usaepay.com/soap/gate/XXXXXXXX"/>
|
31
|
+
# It is also found in the link to your WSDL. This is required as every account has a different path
|
32
|
+
# SOAP requests are submitted to. Optionally, you can provide the entire urls via <tt>:live_url</tt> and <tt>:test_url</tt>, if your prefer.
|
33
|
+
#
|
34
|
+
# ==== Responses
|
35
|
+
# * <tt>#success?</tt> -- +true+ if transmitted and returned correctly
|
36
|
+
# * <tt>#message</tt> -- response or fault message
|
37
|
+
# * <tt>#authorization</tt> -- reference_number or nil
|
38
|
+
# * <tt>#params</tt> -- hash of entire soap response contents
|
39
|
+
#
|
40
|
+
# ==== Address Options
|
41
|
+
# * <tt>:billing_address/:shipping_address</tt> -- contains some extra options
|
42
|
+
# * <tt>:name</tt> -- virtual attribute; will split to first and last name
|
43
|
+
# * <tt>:first_name</tt>
|
44
|
+
# * <tt>:last_name</tt>
|
45
|
+
# * <tt>:address1 </tt>
|
46
|
+
# * <tt>:address2 </tt>
|
47
|
+
# * <tt>:city </tt>
|
48
|
+
# * <tt>:state </tt>
|
49
|
+
# * <tt>:zip </tt>
|
50
|
+
# * <tt>:country </tt>
|
51
|
+
# * <tt>:phone</tt>
|
52
|
+
# * <tt>:email</tt>
|
53
|
+
# * <tt>:fax</tt>
|
54
|
+
# * <tt>:company</tt>
|
55
|
+
#
|
56
|
+
# ==== Support:
|
57
|
+
# * Questions: post to {active_merchant google group}[http://groups.google.com/group/activemerchant]
|
58
|
+
# * Feedback/fixes: matt (at) nearapogee (dot) com
|
59
|
+
#
|
60
|
+
# ==== Links:
|
61
|
+
# * {USA ePay Merchant Console}[https://sandbox.usaepay.com/login]
|
62
|
+
# * {USA ePay Developer Login}[https://www.usaepay.com/developer/login]
|
63
|
+
#
|
64
|
+
class UsaEpayAdvancedGateway < Gateway
|
65
|
+
API_VERSION = "1.4"
|
66
|
+
|
67
|
+
class_attribute :test_url, :live_url
|
68
|
+
|
69
|
+
TEST_URL_BASE = 'https://sandbox.usaepay.com/soap/gate/' #:nodoc:
|
70
|
+
LIVE_URL_BASE = 'https://www.usaepay.com/soap/gate/' #:nodoc:
|
71
|
+
|
72
|
+
FAILURE_MESSAGE = "Default Failure" #:nodoc:
|
73
|
+
|
74
|
+
self.supported_countries = ['US']
|
75
|
+
self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb]
|
76
|
+
self.homepage_url = 'http://www.usaepay.com/'
|
77
|
+
self.display_name = 'USA ePay Advanced SOAP Interface'
|
78
|
+
|
79
|
+
CUSTOMER_OPTIONS = {
|
80
|
+
:id => [:string, 'CustomerID'], # merchant assigned number
|
81
|
+
:notes => [:string, 'Notes'],
|
82
|
+
:data => [:string, 'CustomData'],
|
83
|
+
:url => [:string, 'URL'],
|
84
|
+
# Recurring Billing
|
85
|
+
:enabled => [:boolean, 'Enabled'],
|
86
|
+
:schedule => [:string, 'Schedule'],
|
87
|
+
:number_left => [:integer, 'NumLeft'],
|
88
|
+
:currency => [:string, 'Currency'],
|
89
|
+
:description => [:string, 'Description'],
|
90
|
+
:order_id => [:string, 'OrderID'],
|
91
|
+
:user => [:string, 'User'],
|
92
|
+
:source => [:string, 'Source'],
|
93
|
+
:send_receipt => [:boolean, 'SendReceipt'],
|
94
|
+
:receipt_note => [:string, 'ReceiptNote'],
|
95
|
+
# Point of Sale
|
96
|
+
:price_tier => [:string, 'PriceTier'],
|
97
|
+
:tax_class => [:string, 'TaxClass'],
|
98
|
+
:lookup_code => [:string, 'LookupCode']
|
99
|
+
} #:nodoc:
|
100
|
+
|
101
|
+
ADDRESS_OPTIONS = {
|
102
|
+
:first_name => [:string, 'FirstName'],
|
103
|
+
:last_name => [:string, 'LastName'],
|
104
|
+
:address1 => [:string, 'Street'],
|
105
|
+
:address2 => [:string, 'Street2'],
|
106
|
+
:city => [:string, 'City'],
|
107
|
+
:state => [:string, 'State'],
|
108
|
+
:zip => [:string, 'Zip'],
|
109
|
+
:country => [:string, 'Country'],
|
110
|
+
:phone => [:string, 'Phone'],
|
111
|
+
:email => [:string, 'Email'],
|
112
|
+
:fax => [:string, 'Fax'],
|
113
|
+
:company => [:string, 'Company']
|
114
|
+
} #:nodoc:
|
115
|
+
|
116
|
+
CUSTOMER_TRANSACTION_REQUEST_OPTIONS = {
|
117
|
+
:command => [:string, 'Command'],
|
118
|
+
:ignore_duplicate => [:boolean, 'IgnoreDuplicate'],
|
119
|
+
:client_ip => [:string, 'ClientIP'],
|
120
|
+
:customer_receipt => [:boolean, 'CustReceipt'],
|
121
|
+
:customer_email => [:boolean, 'CustReceiptEmail'],
|
122
|
+
:customer_template => [:boolean, 'CustReceiptName'],
|
123
|
+
:merchant_receipt => [:boolean, 'MerchReceipt'],
|
124
|
+
:merchant_email => [:boolean, 'MerchReceiptEmail'],
|
125
|
+
:merchant_template => [:boolean, 'MerchReceiptName'],
|
126
|
+
:verification_value => [:boolean, 'isRecurring'],
|
127
|
+
:software => [:string, 'Software']
|
128
|
+
} #:nodoc:
|
129
|
+
|
130
|
+
TRANSACTION_REQUEST_OBJECT_OPTIONS = {
|
131
|
+
:command => [:string, 'Command'],
|
132
|
+
:ignore_duplicate => [:boolean, 'IgnoreDuplicate'],
|
133
|
+
:authorization_code => [:string, 'AuthCode'],
|
134
|
+
:reference_number => [:string, 'RefNum'],
|
135
|
+
:account_holder => [:string, 'AccountHolder'],
|
136
|
+
:client_ip => [:string, 'ClientIP'],
|
137
|
+
:customer_id => [:string, 'CustomerID'],
|
138
|
+
:customer_receipt => [:boolean, 'CustReceipt'],
|
139
|
+
:customer_template => [:boolean, 'CustReceiptName'],
|
140
|
+
:software => [:string, 'Software']
|
141
|
+
} #:nodoc:
|
142
|
+
|
143
|
+
TRANSACTION_DETAIL_OPTIONS = {
|
144
|
+
:invoice => [:string, 'Invoice'],
|
145
|
+
:po_number => [:string, 'PONum'],
|
146
|
+
:order_id => [:string, 'OrderID'],
|
147
|
+
:clerk => [:string, 'Clerk'],
|
148
|
+
:terminal => [:string, 'Terminal'],
|
149
|
+
:table => [:string, 'Table'],
|
150
|
+
:description => [:string, 'Description'],
|
151
|
+
:comments => [:string, 'Comments'],
|
152
|
+
:allow_partial_auth => [:boolean, 'AllowPartialAuth'],
|
153
|
+
:currency => [:string, 'Currency'],
|
154
|
+
:non_tax => [:boolean, 'NonTax'],
|
155
|
+
} #:nodoc:
|
156
|
+
|
157
|
+
TRANSACTION_DETAIL_MONEY_OPTIONS = {
|
158
|
+
:amount => [:double, 'Amount'],
|
159
|
+
:tax => [:double, 'Tax'],
|
160
|
+
:tip => [:double, 'Tip'],
|
161
|
+
:non_tax => [:boolean, 'NonTax'],
|
162
|
+
:shipping => [:double, 'Shipping'],
|
163
|
+
:discount => [:double, 'Discount'],
|
164
|
+
:subtotal => [:double, 'Subtotal']
|
165
|
+
} #:nodoc:
|
166
|
+
|
167
|
+
CREDIT_CARD_DATA_OPTIONS = {
|
168
|
+
:magnetic_stripe => [:string, 'MagStripe'],
|
169
|
+
:dukpt => [:string, 'DUKPT'],
|
170
|
+
:signature => [:string, 'Signature'],
|
171
|
+
:terminal_type => [:string, 'TermType'],
|
172
|
+
:magnetic_support => [:string, 'MagSupport'],
|
173
|
+
:xid => [:string, 'XID'],
|
174
|
+
:cavv => [:string, 'CAVV'],
|
175
|
+
:eci => [:integer, 'ECI'],
|
176
|
+
:internal_card_authorization => [:boolean, 'InternalCardAduth'],
|
177
|
+
:pares => [:string, 'Pares']
|
178
|
+
} #:nodoc:
|
179
|
+
|
180
|
+
CHECK_DATA_OPTIONS = {
|
181
|
+
:check_number => [:integer, 'CheckNumber'],
|
182
|
+
:drivers_license => [:string, 'DriversLicense'],
|
183
|
+
:drivers_license_state => [:string, 'DriversLicenseState'],
|
184
|
+
:record_type => [:string, 'RecordType'],
|
185
|
+
:aux_on_us => [:string, 'AuxOnUS'],
|
186
|
+
:epc_code => [:string, 'EpcCode'],
|
187
|
+
:front_image => [:string, 'FrontImage'],
|
188
|
+
:back_image => [:string, 'BackImage']
|
189
|
+
} #:nodoc:
|
190
|
+
|
191
|
+
RECURRING_BILLING_OPTIONS = {
|
192
|
+
:schedule => [:string, 'Schedule'],
|
193
|
+
:number_left => [:integer, 'NumLeft'],
|
194
|
+
:enabled => [:boolean, 'Enabled']
|
195
|
+
} #:nodoc:
|
196
|
+
|
197
|
+
AVS_RESULTS = {
|
198
|
+
'Y' => %w( YYY Y YYA YYD ),
|
199
|
+
'Z' => %w( NYZ Z ),
|
200
|
+
'A' => %w( YNA A YNY ),
|
201
|
+
'N' => %w( NNN N NN ),
|
202
|
+
'X' => %w( YYX X ),
|
203
|
+
'W' => %w( NYW W ),
|
204
|
+
'XXW' => %w( XXW ),
|
205
|
+
'XXU' => %w( XXU ),
|
206
|
+
'R' => %w( XXR R U E ),
|
207
|
+
'S' => %w( XXS S ),
|
208
|
+
'XXE' => %w( XXE ),
|
209
|
+
'G' => %w( XXG G C I ),
|
210
|
+
'B' => %w( YYG B M ),
|
211
|
+
'D' => %w( GGG D ),
|
212
|
+
'P' => %w( YGG P )
|
213
|
+
}.inject({}) do |map, (type, codes)|
|
214
|
+
codes.each { |code| map[code] = type }
|
215
|
+
map
|
216
|
+
end #:nodoc:
|
217
|
+
|
218
|
+
AVS_CUSTOM_MESSAGES = {
|
219
|
+
'XXW' => 'Card number not on file.',
|
220
|
+
'XXU' => 'Address information not verified for domestic transaction.',
|
221
|
+
'XXE' => 'Address verification not allowed for card type.'
|
222
|
+
} #:nodoc:
|
223
|
+
|
224
|
+
# Create a new gateway.
|
225
|
+
#
|
226
|
+
# ==== Required
|
227
|
+
# * At least the live_url OR the software_id must be present.
|
228
|
+
# * <tt>:software_id</tt> -- 8 character software id
|
229
|
+
# OR
|
230
|
+
# * <tt>:test_url</tt> -- full url for testing
|
231
|
+
# * <tt>:live_url</tt> -- full url for live/production
|
232
|
+
#
|
233
|
+
# ==== Optional
|
234
|
+
# * <tt>:soap_response</tt> -- set to +true+ to add :soap_response to the params hash containing the entire soap xml message
|
235
|
+
#
|
236
|
+
def initialize(options = {})
|
237
|
+
requires! options, :login, :password
|
238
|
+
@options = options
|
239
|
+
|
240
|
+
if @options[:software_id]
|
241
|
+
self.live_url = "#{LIVE_URL_BASE}#{@options[:software_id].to_s}"
|
242
|
+
self.test_url = "#{TEST_URL_BASE}#{@options[:software_id].to_s}"
|
243
|
+
else
|
244
|
+
self.live_url = @options[:live_url].to_s
|
245
|
+
self.test_url = @options[:test_url].to_s if @options[:test_url]
|
246
|
+
end
|
247
|
+
|
248
|
+
super
|
249
|
+
end
|
250
|
+
|
251
|
+
# Standard Gateway Methods ======================================
|
252
|
+
|
253
|
+
# Make a purchase with a credit card. (Authorize and
|
254
|
+
# capture for settlement.)
|
255
|
+
#
|
256
|
+
# Note: See run_transaction for additional options.
|
257
|
+
#
|
258
|
+
def purchase(money, creditcard, options={})
|
259
|
+
run_sale(options.merge!(:amount => money, :payment_method => creditcard))
|
260
|
+
end
|
261
|
+
|
262
|
+
# Authorize an amount on a credit card or account.
|
263
|
+
#
|
264
|
+
# Note: See run_transaction for additional options.
|
265
|
+
#
|
266
|
+
def authorize(money, creditcard, options={})
|
267
|
+
run_auth_only(options.merge!(:amount => money, :payment_method => creditcard))
|
268
|
+
end
|
269
|
+
|
270
|
+
# Capture an authorized transaction.
|
271
|
+
#
|
272
|
+
# Note: See run_transaction for additional options.
|
273
|
+
#
|
274
|
+
def capture(money, identification, options={})
|
275
|
+
capture_transaction(options.merge!(:amount => money, :reference_number => identification))
|
276
|
+
end
|
277
|
+
|
278
|
+
# Void a previous transaction that has not been settled.
|
279
|
+
#
|
280
|
+
# Note: See run_transaction for additional options.
|
281
|
+
#
|
282
|
+
def void(identification, options={})
|
283
|
+
void_transaction(options.merge!(:reference_number => identification))
|
284
|
+
end
|
285
|
+
|
286
|
+
# Credit a previous transaction.
|
287
|
+
#
|
288
|
+
# Note: See run_transaction for additional options.
|
289
|
+
#
|
290
|
+
def credit(money, identification, options={})
|
291
|
+
refund_transaction(options.merge!(:amount => money, :reference_number => identification))
|
292
|
+
end
|
293
|
+
|
294
|
+
# Customer ======================================================
|
295
|
+
|
296
|
+
# Add a customer.
|
297
|
+
#
|
298
|
+
# ==== Options
|
299
|
+
# * <tt>:id</tt> -- merchant assigned id
|
300
|
+
# * <tt>:notes</tt> -- notes about customer
|
301
|
+
# * <tt>:data</tt> -- base64 data about customer
|
302
|
+
# * <tt>:url</tt> -- customer website
|
303
|
+
# * <tt>:billing_address</tt> -- usual options
|
304
|
+
# * <tt>:payment_methods</tt> -- array of payment method hashes.
|
305
|
+
# * <tt>:method</tt> -- credit_card or check
|
306
|
+
# * <tt>:name</tt> -- optional name/label for the method
|
307
|
+
# * <tt>:sort</tt> -- optional integer value specifying the backup sort order, 0 is default
|
308
|
+
#
|
309
|
+
# ==== Recurring Options
|
310
|
+
# * <tt>:enabled</tt> -- +true+ enables recurring
|
311
|
+
# * <tt>:schedule</tt> -- daily, weekly, bi-weekly (every two weeks), monthly, bi-monthly (every two months), quarterly, bi-annually (every six months), annually, first of month, last day of month
|
312
|
+
# * <tt>:number_left</tt> -- number of payments left; -1 for unlimited
|
313
|
+
# * <tt>:next</tt> -- date of next payment (Date/Time)
|
314
|
+
# * <tt>:amount</tt> -- amount of recurring payment
|
315
|
+
# * <tt>:tax</tt> -- tax portion of amount
|
316
|
+
# * <tt>:currency</tt> -- numeric currency code
|
317
|
+
# * <tt>:description</tt> -- description of transaction
|
318
|
+
# * <tt>:order_id</tt> -- transaction order id
|
319
|
+
# * <tt>:user</tt> -- merchant username assigned to transaction
|
320
|
+
# * <tt>:source</tt> -- name of source key assigned to billing
|
321
|
+
# * <tt>:send_receipt</tt> -- +true+ to send client a receipt
|
322
|
+
# * <tt>:receipt_note</tt> -- leave a note on the receipt
|
323
|
+
#
|
324
|
+
# ==== Point of Sale Options
|
325
|
+
# * <tt>:price_tier</tt> -- name of customer price tier
|
326
|
+
# * <tt>:tax_class</tt> -- tax class
|
327
|
+
# * <tt>:lookup_code</tt> -- lookup code from customer/member id card; barcode or magnetic stripe; can be assigned by merchant; defaults to system assigned if blank
|
328
|
+
#
|
329
|
+
# ==== Response
|
330
|
+
# * <tt>#message</tt> -- customer number assigned by gateway
|
331
|
+
#
|
332
|
+
def add_customer(options={})
|
333
|
+
request = build_request(__method__, options)
|
334
|
+
commit(__method__, request)
|
335
|
+
end
|
336
|
+
|
337
|
+
# Update a customer by replacing all of the customer details..
|
338
|
+
#
|
339
|
+
# Use quickUpdateCustomer to just update a few attributes.
|
340
|
+
#
|
341
|
+
# ==== Options
|
342
|
+
# * Same as add_customer
|
343
|
+
#
|
344
|
+
def update_customer(options={})
|
345
|
+
requires! options, :customer_number
|
346
|
+
|
347
|
+
request = build_request(__method__, options)
|
348
|
+
commit(__method__, request)
|
349
|
+
end
|
350
|
+
|
351
|
+
# Enable a customer for recurring billing.
|
352
|
+
#
|
353
|
+
# Note: Customer does not need to have all recurring paramerters to succeed.
|
354
|
+
#
|
355
|
+
# ==== Required
|
356
|
+
# * <tt>:customer_number</tt>
|
357
|
+
#
|
358
|
+
def enable_customer(options={})
|
359
|
+
requires! options, :customer_number
|
360
|
+
|
361
|
+
request = build_request(__method__, options)
|
362
|
+
commit(__method__, request)
|
363
|
+
end
|
364
|
+
|
365
|
+
# Disable a customer for recurring billing.
|
366
|
+
#
|
367
|
+
# ==== Required
|
368
|
+
# * <tt>:customer_number</tt>
|
369
|
+
#
|
370
|
+
def disable_customer(options={})
|
371
|
+
requires! options, :customer_number
|
372
|
+
|
373
|
+
request = build_request(__method__, options)
|
374
|
+
commit(__method__, request)
|
375
|
+
end
|
376
|
+
|
377
|
+
# Add a payment method to a customer.
|
378
|
+
#
|
379
|
+
# ==== Required
|
380
|
+
# * <tt>:customer_number</tt> -- number returned by add_customer response.message
|
381
|
+
# * <tt>:payment_method</tt>
|
382
|
+
# * <tt>:method</tt> -- credit_card or check
|
383
|
+
# * <tt>:name</tt> -- optional name/label for the method
|
384
|
+
# * <tt>:sort</tt> -- an integer value specifying the backup sort order, 0 is default
|
385
|
+
#
|
386
|
+
# ==== Optional
|
387
|
+
# * <tt>:make_default</tt> -- set +true+ to make default
|
388
|
+
# * <tt>:verify</tt> -- set +true+ to run auth_only verification; throws fault if cannot verify
|
389
|
+
#
|
390
|
+
# ==== Response
|
391
|
+
# * <tt>#message</tt> -- method_id of new customer payment method
|
392
|
+
#
|
393
|
+
def add_customer_payment_method(options={})
|
394
|
+
requires! options, :customer_number
|
395
|
+
|
396
|
+
request = build_request(__method__, options)
|
397
|
+
commit(__method__, request)
|
398
|
+
end
|
399
|
+
|
400
|
+
# Retrive all of the payment methods belonging to a customer
|
401
|
+
#
|
402
|
+
# ==== Required
|
403
|
+
# * <tt>:customer_number</tt>
|
404
|
+
#
|
405
|
+
# ==== Response
|
406
|
+
# * <tt>#message</tt> -- either a single hash or an array of hashes of payment methods
|
407
|
+
#
|
408
|
+
def get_customer_payment_methods(options={})
|
409
|
+
requires! options, :customer_number
|
410
|
+
|
411
|
+
request = build_request(__method__, options)
|
412
|
+
commit(__method__, request)
|
413
|
+
end
|
414
|
+
|
415
|
+
# Retrive one of the payment methods belonging to a customer
|
416
|
+
#
|
417
|
+
# ==== Required
|
418
|
+
# * <tt>:customer_number</tt>
|
419
|
+
# * <tt>:method_id</tt>
|
420
|
+
#
|
421
|
+
# ==== Response
|
422
|
+
# * <tt>#message</tt> -- hash of payment method
|
423
|
+
#
|
424
|
+
def get_customer_payment_method(options={})
|
425
|
+
requires! options, :customer_number, :method_id
|
426
|
+
|
427
|
+
request = build_request(__method__, options)
|
428
|
+
commit(__method__, request)
|
429
|
+
end
|
430
|
+
|
431
|
+
# Update a customer payment method.
|
432
|
+
#
|
433
|
+
# ==== Required
|
434
|
+
# * <tt>:method_id</tt> -- method_id to update
|
435
|
+
#
|
436
|
+
# ==== Options
|
437
|
+
# * <tt>:method</tt> -- credit_card or check
|
438
|
+
# * <tt>:name</tt> -- optional name/label for the method
|
439
|
+
# * <tt>:sort</tt> -- an integer value specifying the backup sort order, 0 is default
|
440
|
+
# * <tt>:verify</tt> -- set +true+ to run auth_only verification; throws fault if cannot verify
|
441
|
+
#
|
442
|
+
# ==== Response
|
443
|
+
# * <tt>#message</tt> -- hash of payment method
|
444
|
+
#
|
445
|
+
def update_customer_payment_method(options={})
|
446
|
+
requires! options, :method_id
|
447
|
+
|
448
|
+
request = build_request(__method__, options)
|
449
|
+
commit(__method__, request)
|
450
|
+
end
|
451
|
+
|
452
|
+
# Delete one the payment methods beloning to a customer
|
453
|
+
#
|
454
|
+
# ==== Required
|
455
|
+
# * <tt>:customer_number</tt>
|
456
|
+
# * <tt>:method_id</tt>
|
457
|
+
#
|
458
|
+
def delete_customer_payment_method(options={})
|
459
|
+
requires! options, :customer_number, :method_id
|
460
|
+
|
461
|
+
request = build_request(__method__, options)
|
462
|
+
commit(__method__, request)
|
463
|
+
end
|
464
|
+
|
465
|
+
# Delete a customer.
|
466
|
+
#
|
467
|
+
# ==== Required
|
468
|
+
# * <tt>:customer_number</tt>
|
469
|
+
#
|
470
|
+
def delete_customer(options={})
|
471
|
+
requires! options, :customer_number
|
472
|
+
|
473
|
+
request = build_request(__method__, options)
|
474
|
+
commit(__method__, request)
|
475
|
+
end
|
476
|
+
|
477
|
+
# Run a transaction for an existing customer in the database.
|
478
|
+
#
|
479
|
+
# ==== Required Options
|
480
|
+
# * <tt>:customer_number</tt> -- gateway assigned identifier
|
481
|
+
# * <tt>:command</tt> -- Sale, AuthOnly, Credit, Check, CheckCredit
|
482
|
+
# * <tt>:amount</tt> -- total amount
|
483
|
+
#
|
484
|
+
# ==== Options
|
485
|
+
# * <tt>:method_id</tt> -- which payment method to use, 0/nil/omitted for default method
|
486
|
+
# * <tt>:ignore_duplicate</tt> -- +true+ overrides duplicate transaction
|
487
|
+
# * <tt>:client_ip</tt> -- client ip address
|
488
|
+
# * <tt>:customer_receipt</tt> -- +true+, sends receipt to customer. active_merchant defaults to +false+
|
489
|
+
# * <tt>:customer_email</tt> -- specify if different than customer record
|
490
|
+
# * <tt>:customer_template</tt> -- name of template
|
491
|
+
# * <tt>:merchant_receipt</tt> -- +true+, sends receipt to merchant. active_merchant defaults to +false+
|
492
|
+
# * <tt>:merchant_email</tt> -- required if :merchant_receipt set to +true+
|
493
|
+
# * <tt>:merchant_template</tt> -- name of template
|
494
|
+
# * <tt>:recurring</tt> -- defaults to +false+ *see documentation*
|
495
|
+
# * <tt>:verification_value</tt> -- pci forbids storage of this value, only required for CVV2 validation
|
496
|
+
# * <tt>:software</tt> -- active_merchant sets to required gateway option value
|
497
|
+
# * <tt>:line_items</tt> -- XXX not implemented yet
|
498
|
+
# * <tt>:custom_fields</tt> -- XXX not implemented yet
|
499
|
+
#
|
500
|
+
# ==== Transaction Options
|
501
|
+
# * <tt>:invoice</tt> -- transaction invoice number; truncated to 10 characters; defaults to reference_number
|
502
|
+
# * <tt>:po_number</tt> -- commercial purchase order number; upto 25 characters
|
503
|
+
# * <tt>:order_id</tt> -- should be used to assign a unique id; upto 64 characters
|
504
|
+
# * <tt>:clerk</tt> -- sales clerk
|
505
|
+
# * <tt>:terminal</tt> -- terminal name
|
506
|
+
# * <tt>:table</tt> -- table name/number
|
507
|
+
# * <tt>:description</tt> -- description
|
508
|
+
# * <tt>:comments</tt> -- comments
|
509
|
+
# * <tt>:allow_partial_auth</tt> -- allow partial authorization if full amount is not available; defaults +false+
|
510
|
+
# * <tt>:currency</tt> -- numeric currency code
|
511
|
+
# * <tt>:tax</tt> -- tax portion of amount
|
512
|
+
# * <tt>:tip</tt> -- tip portion of amount
|
513
|
+
# * <tt>:non_tax</tt> -- +true+ if transaction is non-taxable
|
514
|
+
# * <tt>:shipping</tt> -- shipping portion of amount
|
515
|
+
# * <tt>:discount</tt> -- amount of discount
|
516
|
+
# * <tt>:subtotal</tt> -- amount of transaction before tax, tip, shipping, and discount are applied
|
517
|
+
#
|
518
|
+
# ==== Response
|
519
|
+
# * <tt>#message</tt> -- transaction response hash
|
520
|
+
#
|
521
|
+
def run_customer_transaction(options={})
|
522
|
+
requires! options, :customer_number, :command, :amount
|
523
|
+
|
524
|
+
request = build_request(__method__, options)
|
525
|
+
commit(__method__, request)
|
526
|
+
end
|
527
|
+
|
528
|
+
# Transactions ==================================================
|
529
|
+
|
530
|
+
# Run a transaction.
|
531
|
+
#
|
532
|
+
# Note: run_sale, run_auth_only, run_credit, run_check_sale, run_check_credit
|
533
|
+
# methods are also available. Each takes the same options as
|
534
|
+
# run_transaction, but the :command option is not required.
|
535
|
+
#
|
536
|
+
# Recurring Note: If recurring options are included USA ePay will create a
|
537
|
+
# new customer record with the supplied information. The customer number
|
538
|
+
# will be returned in the response.
|
539
|
+
#
|
540
|
+
# ==== Options
|
541
|
+
# * <tt>:method</tt> -- credit_card or check
|
542
|
+
# * <tt>:command</tt> -- sale, credit, void, creditvoid, authonly, capture, postauth, check, checkcredit; defaults to sale; only required for run_transaction when other than sale
|
543
|
+
# * <tt>:reference_number</tt> -- for the original transaction; obtained by sale or authonly
|
544
|
+
# * <tt>:authorization_code</tt> -- required for postauth; obtained offline
|
545
|
+
# * <tt>:ignore_duplicate</tt> -- set +true+ if you want to override the duplicate tranaction handling
|
546
|
+
# * <tt>:account_holder</tt> -- name of account holder
|
547
|
+
# * <tt>:customer_id</tt> -- merchant assigned id
|
548
|
+
# * <tt>:customer_receipt</tt> -- set +true+ to email receipt to billing email address
|
549
|
+
# * <tt>:customer_template</tt> -- name of template
|
550
|
+
# * <tt>:software</tt> -- stamp merchant software version for tracking
|
551
|
+
# * <tt>:billing_address</tt> -- see UsaEpayCimGateway documentation for all address fields
|
552
|
+
# * <tt>:shipping_address</tt> -- see UsaEpayCimGateway documentation for all address fields
|
553
|
+
# * <tt>:recurring</tt> -- used for recurring billing transactions
|
554
|
+
# * <tt>:schedule</tt> -- disabled, daily, weekly, bi-weekly (every two weeks), monthly, bi-monthly (every two months), quarterly, bi-annually (every six months), annually
|
555
|
+
# * <tt>:next</tt> -- date customer billed next (Date/Time)
|
556
|
+
# * <tt>:expire</tt> -- date the recurring transactions end (Date/Time)
|
557
|
+
# * <tt>:number_left</tt> -- transactions remaining in billing cycle
|
558
|
+
# * <tt>:amount</tt> -- amount to be billed each recurring transaction
|
559
|
+
# * <tt>:enabled</tt> -- states if currently active
|
560
|
+
# * <tt>:line_items</tt> -- XXX not implemented yet
|
561
|
+
# * <tt>:custom_fields</tt> -- XXX not implemented yet
|
562
|
+
#
|
563
|
+
# ==== Transaction Options
|
564
|
+
# * <tt>:amount</tt> -- total amount
|
565
|
+
# * <tt>:invoice</tt> -- transaction invoice number; truncated to 10 characters; defaults to reference_number
|
566
|
+
# * <tt>:po_number</tt> -- commercial purchase order number; upto 25 characters
|
567
|
+
# * <tt>:order_id</tt> -- should be used to assign a unique id; upto 64 characters
|
568
|
+
# * <tt>:clerk</tt> -- sales clerk
|
569
|
+
# * <tt>:terminal</tt> -- terminal name
|
570
|
+
# * <tt>:table</tt> -- table name/number
|
571
|
+
# * <tt>:description</tt> -- description
|
572
|
+
# * <tt>:comments</tt> -- comments
|
573
|
+
# * <tt>:allow_partial_auth</tt> -- allow partial authorization if full amount is not available; defaults +false+
|
574
|
+
# * <tt>:currency</tt> -- numeric currency code
|
575
|
+
# * <tt>:tax</tt> -- tax portion of amount
|
576
|
+
# * <tt>:tip</tt> -- tip portion of amount
|
577
|
+
# * <tt>:non_tax</tt> -- +true+ if transaction is non-taxable
|
578
|
+
# * <tt>:shipping</tt> -- shipping portion of amount
|
579
|
+
# * <tt>:discount</tt> -- amount of discount
|
580
|
+
# * <tt>:subtotal</tt> -- amount of transaction before tax, tip, shipping, and discount are applied
|
581
|
+
#
|
582
|
+
# ==== Response
|
583
|
+
# * <tt>#message</tt> -- transaction response hash
|
584
|
+
#
|
585
|
+
def run_transaction(options={})
|
586
|
+
request = build_request(__method__, options)
|
587
|
+
commit(__method__, request)
|
588
|
+
end
|
589
|
+
|
590
|
+
TRANSACTION_METHODS = [
|
591
|
+
:run_sale, :run_auth_only, :run_credit,
|
592
|
+
:run_check_sale, :run_check_credit
|
593
|
+
] #:nodoc:
|
594
|
+
|
595
|
+
TRANSACTION_METHODS.each do |method|
|
596
|
+
define_method method do |options|
|
597
|
+
request = build_request(method, options)
|
598
|
+
commit(method, request)
|
599
|
+
end
|
600
|
+
end
|
601
|
+
|
602
|
+
# Post an authorization code obtained offline.
|
603
|
+
#
|
604
|
+
# ==== Required
|
605
|
+
# * <tt>:authorization_code</tt> -- obtained offline
|
606
|
+
#
|
607
|
+
# ==== Options
|
608
|
+
# * Same as run_transaction
|
609
|
+
#
|
610
|
+
# ==== Response
|
611
|
+
# * <tt>#message</tt> -- transaction response hash
|
612
|
+
#
|
613
|
+
def post_auth(options={})
|
614
|
+
requires! options, :authorization_code
|
615
|
+
|
616
|
+
request = build_request(__method__, options)
|
617
|
+
commit(__method__, request)
|
618
|
+
end
|
619
|
+
|
620
|
+
# Capture an authorized transaction and move it into the current batch
|
621
|
+
# for settlement.
|
622
|
+
#
|
623
|
+
# Note: Check with merchant bank for details/restrictions on differing
|
624
|
+
# amounts than the original authorization.
|
625
|
+
#
|
626
|
+
# ==== Required
|
627
|
+
# * <tt>:reference_number</tt>
|
628
|
+
#
|
629
|
+
# ==== Options
|
630
|
+
# * <tt>:amount</tt> -- may be different than original amount; 0 will void authorization
|
631
|
+
#
|
632
|
+
# ==== Response
|
633
|
+
# * <tt>#message</tt> -- transaction response hash
|
634
|
+
#
|
635
|
+
def capture_transaction(options={})
|
636
|
+
requires! options, :reference_number
|
637
|
+
|
638
|
+
request = build_request(__method__, options)
|
639
|
+
commit(__method__, request)
|
640
|
+
end
|
641
|
+
|
642
|
+
# Void a transaction.
|
643
|
+
#
|
644
|
+
# Note: Can only be voided before being settled.
|
645
|
+
#
|
646
|
+
# ==== Required
|
647
|
+
# * <tt>:reference_number</tt>
|
648
|
+
#
|
649
|
+
# ==== Response
|
650
|
+
# * <tt>#message</tt> -- transaction response hash
|
651
|
+
#
|
652
|
+
def void_transaction(options={})
|
653
|
+
requires! options, :reference_number
|
654
|
+
|
655
|
+
request = build_request(__method__, options)
|
656
|
+
commit(__method__, request)
|
657
|
+
end
|
658
|
+
|
659
|
+
# Refund transaction.
|
660
|
+
#
|
661
|
+
# Note: Required after a transaction has been settled. Refunds
|
662
|
+
# both credit card and check transactions.
|
663
|
+
#
|
664
|
+
# ==== Required
|
665
|
+
# * <tt>:reference_number</tt>
|
666
|
+
# * <tt>:amount</tt> -- amount to refund; 0 will refund original amount
|
667
|
+
#
|
668
|
+
# ==== Response
|
669
|
+
# * <tt>#message</tt> -- transaction response hash
|
670
|
+
#
|
671
|
+
def refund_transaction(options={})
|
672
|
+
requires! options, :reference_number, :amount
|
673
|
+
|
674
|
+
request = build_request(__method__, options)
|
675
|
+
commit(__method__, request)
|
676
|
+
end
|
677
|
+
|
678
|
+
# Override transaction flagged for mananager approval.
|
679
|
+
#
|
680
|
+
# Note: Checks only!
|
681
|
+
#
|
682
|
+
# ==== Required
|
683
|
+
# * <tt>:reference_number</tt>
|
684
|
+
#
|
685
|
+
# ==== Options
|
686
|
+
# * <tt>:reason</tt>
|
687
|
+
#
|
688
|
+
# ==== Response
|
689
|
+
# * <tt>#message</tt> -- transaction response hash
|
690
|
+
#
|
691
|
+
def override_transaction(options={})
|
692
|
+
requires! options, :reference_number
|
693
|
+
|
694
|
+
request = build_request(__method__, options)
|
695
|
+
commit(__method__, request)
|
696
|
+
end
|
697
|
+
|
698
|
+
# Quick Transactions ============================================
|
699
|
+
|
700
|
+
# Run a sale transaction based off of a past transaction.
|
701
|
+
#
|
702
|
+
# Transfers referenced transaction's payment method to this
|
703
|
+
# transaction. As of 6/2011, USA ePay blocks credit card numbers
|
704
|
+
# at 3 years.
|
705
|
+
#
|
706
|
+
# ==== Required
|
707
|
+
# * <tt>:reference_number</tt> -- transaction to reference payment from
|
708
|
+
# * <tt>:amount</tt> -- total amount
|
709
|
+
#
|
710
|
+
# ==== Options
|
711
|
+
# * <tt>:authorize_only</tt> -- set +true+ if you just want to authorize
|
712
|
+
#
|
713
|
+
# ==== Transaction Options
|
714
|
+
# * <tt>:invoice</tt> -- transaction invoice number; truncated to 10 characters; defaults to reference_number
|
715
|
+
# * <tt>:po_number</tt> -- commercial purchase order number; upto 25 characters
|
716
|
+
# * <tt>:order_id</tt> -- should be used to assign a unique id; upto 64 characters
|
717
|
+
# * <tt>:clerk</tt> -- sales clerk
|
718
|
+
# * <tt>:terminal</tt> -- terminal name
|
719
|
+
# * <tt>:table</tt> -- table name/number
|
720
|
+
# * <tt>:description</tt> -- description
|
721
|
+
# * <tt>:comments</tt> -- comments
|
722
|
+
# * <tt>:allow_partial_auth</tt> -- allow partial authorization if full amount is not available; defaults +false+
|
723
|
+
# * <tt>:currency</tt> -- numeric currency code
|
724
|
+
# * <tt>:tax</tt> -- tax portion of amount
|
725
|
+
# * <tt>:tip</tt> -- tip portion of amount
|
726
|
+
# * <tt>:non_tax</tt> -- +true+ if transaction is non-taxable
|
727
|
+
# * <tt>:shipping</tt> -- shipping portion of amount
|
728
|
+
# * <tt>:discount</tt> -- amount of discount
|
729
|
+
# * <tt>:subtotal</tt> -- amount of transaction before tax, tip, shipping, and discount are applied
|
730
|
+
#
|
731
|
+
# ==== Response
|
732
|
+
# * <tt>#message</tt> -- transaction response hash
|
733
|
+
#
|
734
|
+
def run_quick_sale(options={})
|
735
|
+
requires! options, :reference_number, :amount
|
736
|
+
|
737
|
+
request = build_request(__method__, options)
|
738
|
+
commit(__method__, request)
|
739
|
+
end
|
740
|
+
|
741
|
+
# Run a credit based off of a past transaction.
|
742
|
+
#
|
743
|
+
# Transfers referenced transaction's payment method to this
|
744
|
+
# transaction. As of 6/2011, USA ePay blocks credit card numbers
|
745
|
+
# at 3 years.
|
746
|
+
#
|
747
|
+
# ==== Required
|
748
|
+
# * <tt>:reference_number</tt> -- transaction to reference payment from
|
749
|
+
#
|
750
|
+
# ==== Transaction Options
|
751
|
+
# * <tt>:amount</tt> -- total amount
|
752
|
+
# * <tt>:invoice</tt> -- transaction invoice number; truncated to 10 characters; defaults to reference_number
|
753
|
+
# * <tt>:po_number</tt> -- commercial purchase order number; upto 25 characters
|
754
|
+
# * <tt>:order_id</tt> -- should be used to assign a unique id; upto 64 characters
|
755
|
+
# * <tt>:clerk</tt> -- sales clerk
|
756
|
+
# * <tt>:terminal</tt> -- terminal name
|
757
|
+
# * <tt>:table</tt> -- table name/number
|
758
|
+
# * <tt>:description</tt> -- description
|
759
|
+
# * <tt>:comments</tt> -- comments
|
760
|
+
# * <tt>:allow_partial_auth</tt> -- allow partial authorization if full amount is not available; defaults +false+
|
761
|
+
# * <tt>:currency</tt> -- numeric currency code
|
762
|
+
# * <tt>:tax</tt> -- tax portion of amount
|
763
|
+
# * <tt>:tip</tt> -- tip portion of amount
|
764
|
+
# * <tt>:non_tax</tt> -- +true+ if transaction is non-taxable
|
765
|
+
# * <tt>:shipping</tt> -- shipping portion of amount
|
766
|
+
# * <tt>:discount</tt> -- amount of discount
|
767
|
+
# * <tt>:subtotal</tt> -- amount of transaction before tax, tip, shipping, and discount are applied
|
768
|
+
#
|
769
|
+
# ==== Response
|
770
|
+
# * <tt>#message</tt> -- transaction response hash
|
771
|
+
#
|
772
|
+
def run_quick_credit(options={})
|
773
|
+
requires! options, :reference_number
|
774
|
+
|
775
|
+
request = build_request(__method__, options)
|
776
|
+
commit(__method__, request)
|
777
|
+
end
|
778
|
+
|
779
|
+
# Transaction Status ============================================
|
780
|
+
|
781
|
+
# Retrieve details of a specified transaction.
|
782
|
+
#
|
783
|
+
# ==== Required
|
784
|
+
# * <tt>:reference_number</tt>
|
785
|
+
#
|
786
|
+
# ==== Response
|
787
|
+
# * <tt>#message</tt> -- transaction hash
|
788
|
+
#
|
789
|
+
def get_transaction(options={})
|
790
|
+
requires! options, :reference_number
|
791
|
+
|
792
|
+
request = build_request(__method__, options)
|
793
|
+
commit(__method__, request)
|
794
|
+
end
|
795
|
+
|
796
|
+
# Check status of a transaction.
|
797
|
+
#
|
798
|
+
# ==== Required
|
799
|
+
# * <tt>:reference_number</tt>
|
800
|
+
#
|
801
|
+
# ==== Response
|
802
|
+
# * <tt>response.success</tt> -- success of the referenced transaction
|
803
|
+
# * <tt>response.message</tt> -- message of the referenced transaction
|
804
|
+
# * <tt>response.authorization</tt> -- same as :reference_number in options
|
805
|
+
#
|
806
|
+
def get_transaction_status(options={})
|
807
|
+
requires! options, :reference_number
|
808
|
+
|
809
|
+
request = build_request(__method__, options)
|
810
|
+
commit(__method__, request)
|
811
|
+
end
|
812
|
+
|
813
|
+
# Check status of a transaction (custom).
|
814
|
+
#
|
815
|
+
# ==== Required
|
816
|
+
# * <tt>:reference_number</tt>
|
817
|
+
# * <tt>:fields</tt> -- string array of fields to retrieve
|
818
|
+
# * <tt>Response.AuthCode</tt>
|
819
|
+
# * <tt>Response.AvsResult</tt>
|
820
|
+
# * <tt>Response.AvsResultCode</tt>
|
821
|
+
# * <tt>Response.BatchNum</tt>
|
822
|
+
# * <tt>Response.CardCodeResult</tt>
|
823
|
+
# * <tt>Response.CardCodeResultCode</tt>
|
824
|
+
# * <tt>Response.ConversionRate</tt>
|
825
|
+
# * <tt>Response.ConvertedAmount</tt>
|
826
|
+
# * <tt>Response.ConvertedAmountCurrency</tt>
|
827
|
+
# * <tt>Response.Error</tt>
|
828
|
+
# * <tt>Response.ErrorCode</tt>
|
829
|
+
# * <tt>Response.RefNum</tt>
|
830
|
+
# * <tt>Response.Result</tt>
|
831
|
+
# * <tt>Response.ResultCode</tt>
|
832
|
+
# * <tt>Response.Status</tt>
|
833
|
+
# * <tt>Response.StatusCode</tt>
|
834
|
+
# * <tt>CheckTrace.TrackingNum</tt>
|
835
|
+
# * <tt>CheckTrace.Effective</tt>
|
836
|
+
# * <tt>CheckTrace.Processed</tt>
|
837
|
+
# * <tt>CheckTrace.Settled</tt>
|
838
|
+
# * <tt>CheckTrace.Returned</tt>
|
839
|
+
# * <tt>CheckTrace.BankNote</tt>
|
840
|
+
# * <tt>DateTime</tt>
|
841
|
+
# * <tt>AccountHolder</tt>
|
842
|
+
# * <tt>Details.Invoice</tt>
|
843
|
+
# * <tt>Details.PoNum</tt>
|
844
|
+
# * <tt>Details.OrderID</tt>
|
845
|
+
# * <tt>Details.Clerk</tt>
|
846
|
+
# * <tt>Details.Terminal</tt>
|
847
|
+
# * <tt>Details.Table</tt>
|
848
|
+
# * <tt>Details.Description</tt>
|
849
|
+
# * <tt>Details.Amount</tt>
|
850
|
+
# * <tt>Details.Currency</tt>
|
851
|
+
# * <tt>Details.Tax</tt>
|
852
|
+
# * <tt>Details.Tip</tt>
|
853
|
+
# * <tt>Details.NonTax</tt>
|
854
|
+
# * <tt>Details.Shipping</tt>
|
855
|
+
# * <tt>Details.Discount</tt>
|
856
|
+
# * <tt>Details.Subtotal</tt>
|
857
|
+
# * <tt>CreditCardData.CardType</tt>
|
858
|
+
# * <tt>CreditCardData.CardNumber</tt>
|
859
|
+
# * <tt>CreditCardData.CardExpiration</tt>
|
860
|
+
# * <tt>CreditCardData.CardCode</tt>
|
861
|
+
# * <tt>CreditCardData.AvsStreet</tt>
|
862
|
+
# * <tt>CreditCardData.AvsZip</tt>
|
863
|
+
# * <tt>CreditCardData.CardPresent</tt>
|
864
|
+
# * <tt>CheckData.CheckNumber</tt>
|
865
|
+
# * <tt>CheckData.Routing</tt>
|
866
|
+
# * <tt>CheckData.Account</tt>
|
867
|
+
# * <tt>CheckData.SSN</tt>
|
868
|
+
# * <tt>CheckData.DriversLicense</tt>
|
869
|
+
# * <tt>CheckData.DriversLicenseState</tt>
|
870
|
+
# * <tt>CheckData.RecordType</tt>
|
871
|
+
# * <tt>User</tt>
|
872
|
+
# * <tt>Source</tt>
|
873
|
+
# * <tt>ServerIP</tt>
|
874
|
+
# * <tt>ClientIP</tt>
|
875
|
+
# * <tt>CustomerID</tt>
|
876
|
+
# * <tt>BillingAddress.FirstName</tt>
|
877
|
+
# * <tt>BillingAddress.LastName</tt>
|
878
|
+
# * <tt>BillingAddress.Company</tt>
|
879
|
+
# * <tt>BillingAddress.Street</tt>
|
880
|
+
# * <tt>BillingAddress.Street2</tt>
|
881
|
+
# * <tt>BillingAddress.City</tt>
|
882
|
+
# * <tt>BillingAddress.State</tt>
|
883
|
+
# * <tt>BillingAddress.Zip</tt>
|
884
|
+
# * <tt>BillingAddress.Country</tt>
|
885
|
+
# * <tt>BillingAddress.Phone</tt>
|
886
|
+
# * <tt>BillingAddress.Fax</tt>
|
887
|
+
# * <tt>BillingAddress.Email</tt>
|
888
|
+
# * <tt>ShippingAddress.FirstName</tt>
|
889
|
+
# * <tt>ShippingAddress.LastName</tt>
|
890
|
+
# * <tt>ShippingAddress.Company</tt>
|
891
|
+
# * <tt>ShippingAddress.Street</tt>
|
892
|
+
# * <tt>ShippingAddress.Street2</tt>
|
893
|
+
# * <tt>ShippingAddress.City</tt>
|
894
|
+
# * <tt>ShippingAddress.State</tt>
|
895
|
+
# * <tt>ShippingAddress.Zip</tt>
|
896
|
+
# * <tt>ShippingAddress.Country</tt>
|
897
|
+
# * <tt>ShippingAddress.Phone</tt>
|
898
|
+
# * <tt>ShippingAddress.Fax</tt>
|
899
|
+
# * <tt>ShippingAddress.Email</tt>
|
900
|
+
#
|
901
|
+
# ==== Response
|
902
|
+
# * <tt>#message</tt> -- hash; keys are the field values
|
903
|
+
#
|
904
|
+
def get_transaction_custom(options={})
|
905
|
+
requires! options, :reference_number, :fields
|
906
|
+
|
907
|
+
request = build_request(__method__, options)
|
908
|
+
commit(__method__, request)
|
909
|
+
end
|
910
|
+
|
911
|
+
# Check status of a check transaction.
|
912
|
+
#
|
913
|
+
# ==== Required
|
914
|
+
# * <tt>:reference_number</tt>
|
915
|
+
#
|
916
|
+
# ==== Response
|
917
|
+
# * <tt>#message</tt> -- check trace hash
|
918
|
+
#
|
919
|
+
def get_check_trace(options={})
|
920
|
+
requires! options, :reference_number
|
921
|
+
|
922
|
+
request = build_request(__method__, options)
|
923
|
+
commit(__method__, request)
|
924
|
+
end
|
925
|
+
|
926
|
+
# Account =======================================================
|
927
|
+
|
928
|
+
# Retrieve merchant account details
|
929
|
+
#
|
930
|
+
# ==== Response
|
931
|
+
# * <tt>#message</tt> -- account hash
|
932
|
+
#
|
933
|
+
def get_account_details
|
934
|
+
request = build_request(__method__)
|
935
|
+
commit(__method__, request)
|
936
|
+
end
|
937
|
+
|
938
|
+
# Builders ======================================================
|
939
|
+
|
940
|
+
private
|
941
|
+
|
942
|
+
# Build soap header, etc.
|
943
|
+
def build_request(action, options = {})
|
944
|
+
soap = Builder::XmlMarkup.new
|
945
|
+
soap.instruct!(:xml, :version => '1.0', :encoding => 'utf-8')
|
946
|
+
soap.tag! "SOAP-ENV:Envelope",
|
947
|
+
'xmlns:SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/',
|
948
|
+
'xmlns:ns1' => 'urn:usaepay',
|
949
|
+
'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema',
|
950
|
+
'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
|
951
|
+
'xmlns:SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/',
|
952
|
+
'SOAP-ENV:encodingStyle' => 'http://schemas.xmlsoap.org/soap/encoding/' do |soap|
|
953
|
+
soap.tag! "SOAP-ENV:Body" do |soap|
|
954
|
+
send("build_#{action}", soap, options)
|
955
|
+
end
|
956
|
+
end
|
957
|
+
soap.target!
|
958
|
+
end
|
959
|
+
|
960
|
+
# Build generic tag.
|
961
|
+
def build_tag(soap, type, tag, value)
|
962
|
+
soap.tag!(tag, value, 'xsi:type' => "xsd:#{type}") if value != nil
|
963
|
+
end
|
964
|
+
|
965
|
+
# Build token.
|
966
|
+
def build_token(soap, options)
|
967
|
+
seed = SecureRandom.base64(32)
|
968
|
+
hash = Digest::SHA1.hexdigest("#{@options[:login]}#{seed}#{@options[:password].to_s.strip}")
|
969
|
+
soap.Token 'xsi:type' => 'ns1:ueSecurityToken' do |soap|
|
970
|
+
build_tag soap, :string, 'ClientIP', options[:client_ip]
|
971
|
+
soap.PinHash 'xsi:type' => 'ns1:ueHash' do |soap|
|
972
|
+
build_tag soap, :string, "HashValue", hash
|
973
|
+
build_tag soap, :string, "Seed", seed
|
974
|
+
build_tag soap, :string, "Type", 'sha1'
|
975
|
+
end
|
976
|
+
build_tag soap, :string, 'SourceKey', @options[:login]
|
977
|
+
end
|
978
|
+
end
|
979
|
+
|
980
|
+
# Customer ======================================================
|
981
|
+
|
982
|
+
def build_add_customer(soap, options)
|
983
|
+
soap.tag! "ns1:addCustomer" do |soap|
|
984
|
+
build_token soap, options
|
985
|
+
build_customer_data soap, options
|
986
|
+
build_tag soap, :double, 'Amount', amount(options[:amount])
|
987
|
+
build_tag soap, :double, 'Tax', amount(options[:tax])
|
988
|
+
build_tag soap, :string, 'Next', options[:next].strftime("%Y-%m-%d") if options[:next]
|
989
|
+
end
|
990
|
+
end
|
991
|
+
|
992
|
+
def build_customer(soap, options, type, add_customer_data=false)
|
993
|
+
soap.tag! "ns1:#{type}" do |soap|
|
994
|
+
build_token soap, options
|
995
|
+
build_tag soap, :integer, 'CustNum', options[:customer_number]
|
996
|
+
build_customer_data soap, options if add_customer_data
|
997
|
+
end
|
998
|
+
end
|
999
|
+
|
1000
|
+
def build_update_customer(soap, options)
|
1001
|
+
build_customer(soap, options, 'updateCustomer', true)
|
1002
|
+
end
|
1003
|
+
|
1004
|
+
def build_enable_customer(soap, options)
|
1005
|
+
build_customer(soap, options, 'enableCustomer')
|
1006
|
+
end
|
1007
|
+
|
1008
|
+
def build_disable_customer(soap, options)
|
1009
|
+
build_customer(soap, options, 'disableCustomer')
|
1010
|
+
end
|
1011
|
+
|
1012
|
+
def build_delete_customer(soap, options)
|
1013
|
+
build_customer(soap, options, 'deleteCustomer')
|
1014
|
+
end
|
1015
|
+
|
1016
|
+
def build_add_customer_payment_method(soap, options)
|
1017
|
+
soap.tag! "ns1:addCustomerPaymentMethod" do |soap|
|
1018
|
+
build_token soap, options
|
1019
|
+
build_tag soap, :integer, 'CustNum', options[:customer_number]
|
1020
|
+
build_customer_payment_methods soap, options
|
1021
|
+
build_tag soap, :boolean, 'MakeDefault', options[:make_default]
|
1022
|
+
build_tag soap, :boolean, 'Verify', options[:verify]
|
1023
|
+
end
|
1024
|
+
end
|
1025
|
+
|
1026
|
+
def build_get_customer_payment_method(soap, options)
|
1027
|
+
soap.tag! 'ns1:getCustomerPaymentMethod' do |soap|
|
1028
|
+
build_token soap, options
|
1029
|
+
build_tag soap, :integer, 'CustNum', options[:customer_number]
|
1030
|
+
build_tag soap, :integer, 'MethodID', options[:method_id]
|
1031
|
+
end
|
1032
|
+
end
|
1033
|
+
|
1034
|
+
def build_get_customer_payment_methods(soap, options)
|
1035
|
+
build_customer(soap, options, 'getCustomerPaymentMethods')
|
1036
|
+
end
|
1037
|
+
|
1038
|
+
def build_update_customer_payment_method(soap, options)
|
1039
|
+
soap.tag! 'ns1:updateCustomerPaymentMethod' do |soap|
|
1040
|
+
build_token soap, options
|
1041
|
+
build_customer_payment_methods soap, options
|
1042
|
+
build_tag soap, :boolean, 'Verify', options[:verify]
|
1043
|
+
end
|
1044
|
+
end
|
1045
|
+
|
1046
|
+
def build_delete_customer_payment_method(soap, options)
|
1047
|
+
soap.tag! "ns1:deleteCustomerPaymentMethod" do |soap|
|
1048
|
+
build_token soap, options
|
1049
|
+
build_tag soap, :integer, 'Custnum', options[:customer_number]
|
1050
|
+
build_tag soap, :integer, 'PaymentMethodID', options[:method_id]
|
1051
|
+
end
|
1052
|
+
end
|
1053
|
+
|
1054
|
+
def build_run_customer_transaction(soap, options)
|
1055
|
+
soap.tag! "ns1:runCustomerTransaction" do |soap|
|
1056
|
+
build_token soap, options
|
1057
|
+
build_tag soap, :integer, 'CustNum', options[:customer_number]
|
1058
|
+
build_tag soap, :integer, 'PaymentMethodID', options[:method_id] || 0
|
1059
|
+
build_customer_transaction soap, options
|
1060
|
+
end
|
1061
|
+
end
|
1062
|
+
|
1063
|
+
# Transactions ==================================================
|
1064
|
+
|
1065
|
+
def build_run_transaction(soap, options)
|
1066
|
+
soap.tag! 'ns1:runTransaction' do |soap|
|
1067
|
+
build_token soap, options
|
1068
|
+
build_transaction_request_object soap, options, 'Parameters'
|
1069
|
+
end
|
1070
|
+
end
|
1071
|
+
|
1072
|
+
def build_run_sale(soap, options)
|
1073
|
+
soap.tag! 'ns1:runSale' do |soap|
|
1074
|
+
build_token soap, options
|
1075
|
+
build_transaction_request_object soap, options
|
1076
|
+
end
|
1077
|
+
end
|
1078
|
+
|
1079
|
+
def build_run_auth_only(soap, options)
|
1080
|
+
soap.tag! 'ns1:runAuthOnly' do |soap|
|
1081
|
+
build_token soap, options
|
1082
|
+
build_transaction_request_object soap, options
|
1083
|
+
end
|
1084
|
+
end
|
1085
|
+
|
1086
|
+
def build_run_credit(soap, options)
|
1087
|
+
soap.tag! 'ns1:runCredit' do |soap|
|
1088
|
+
build_token soap, options
|
1089
|
+
build_transaction_request_object soap, options
|
1090
|
+
end
|
1091
|
+
end
|
1092
|
+
|
1093
|
+
def build_run_check_sale(soap, options)
|
1094
|
+
soap.tag! 'ns1:runCheckSale' do |soap|
|
1095
|
+
build_token soap, options
|
1096
|
+
build_transaction_request_object soap, options
|
1097
|
+
end
|
1098
|
+
end
|
1099
|
+
|
1100
|
+
def build_run_check_credit(soap, options)
|
1101
|
+
soap.tag! 'ns1:runCheckCredit' do |soap|
|
1102
|
+
build_token soap, options
|
1103
|
+
build_transaction_request_object soap, options
|
1104
|
+
end
|
1105
|
+
end
|
1106
|
+
|
1107
|
+
def build_post_auth(soap, options)
|
1108
|
+
soap.tag! 'ns1:postAuth' do |soap|
|
1109
|
+
build_token soap, options
|
1110
|
+
build_transaction_request_object soap, options
|
1111
|
+
end
|
1112
|
+
end
|
1113
|
+
|
1114
|
+
def build_run_quick_sale(soap, options)
|
1115
|
+
soap.tag! 'ns1:runQuickSale' do |soap|
|
1116
|
+
build_token soap, options
|
1117
|
+
build_tag soap, :integer, 'RefNum', options[:reference_number]
|
1118
|
+
build_transaction_detail soap, options
|
1119
|
+
build_tag soap, :boolean, 'AuthOnly', options[:authorize_only] || false
|
1120
|
+
end
|
1121
|
+
end
|
1122
|
+
|
1123
|
+
def build_run_quick_credit(soap, options)
|
1124
|
+
soap.tag! 'ns1:runQuickCredit' do |soap|
|
1125
|
+
build_token soap, options
|
1126
|
+
build_tag soap, :integer, 'RefNum', options[:reference_number]
|
1127
|
+
build_transaction_detail soap, options
|
1128
|
+
end
|
1129
|
+
end
|
1130
|
+
|
1131
|
+
def build_get_transaction(soap, options)
|
1132
|
+
soap.tag! "ns1:getTransaction" do |soap|
|
1133
|
+
build_token soap, options
|
1134
|
+
build_tag soap, :integer, 'RefNum', options[:reference_number]
|
1135
|
+
end
|
1136
|
+
end
|
1137
|
+
|
1138
|
+
def build_get_transaction_status(soap, options)
|
1139
|
+
soap.tag! "ns1:getTransactionStatus" do |soap|
|
1140
|
+
build_token soap, options
|
1141
|
+
build_tag soap, :integer, 'RefNum', options[:reference_number]
|
1142
|
+
end
|
1143
|
+
end
|
1144
|
+
|
1145
|
+
def build_get_transaction_custom(soap, options)
|
1146
|
+
soap.tag! "ns1:getTransactionCustom" do |soap|
|
1147
|
+
build_token soap, options
|
1148
|
+
build_tag soap, :integer, 'RefNum', options[:reference_number]
|
1149
|
+
build_transaction_field_array soap, options
|
1150
|
+
end
|
1151
|
+
end
|
1152
|
+
|
1153
|
+
def build_get_check_trace(soap, options)
|
1154
|
+
soap.tag! "ns1:getCheckTrace" do |soap|
|
1155
|
+
build_token soap, options
|
1156
|
+
build_tag soap, :integer, 'RefNum', options[:reference_number]
|
1157
|
+
end
|
1158
|
+
end
|
1159
|
+
|
1160
|
+
def build_capture_transaction(soap, options)
|
1161
|
+
soap.tag! "ns1:captureTransaction" do |soap|
|
1162
|
+
build_token soap, options
|
1163
|
+
build_tag soap, :integer, 'RefNum', options[:reference_number]
|
1164
|
+
build_tag soap, :double, 'RefNum', amount(options[:amount])
|
1165
|
+
end
|
1166
|
+
end
|
1167
|
+
|
1168
|
+
def build_void_transaction(soap, options)
|
1169
|
+
soap.tag! "ns1:voidTransaction" do |soap|
|
1170
|
+
build_token soap, options
|
1171
|
+
build_tag soap, :integer, 'RefNum', options[:reference_number]
|
1172
|
+
end
|
1173
|
+
end
|
1174
|
+
|
1175
|
+
def build_refund_transaction(soap, options)
|
1176
|
+
soap.tag! "ns1:refundTransaction" do |soap|
|
1177
|
+
build_token soap, options
|
1178
|
+
build_tag soap, :integer, 'RefNum', options[:reference_number]
|
1179
|
+
build_tag soap, :integer, 'Amount', amount(options[:amount])
|
1180
|
+
end
|
1181
|
+
end
|
1182
|
+
|
1183
|
+
def build_override_transaction(soap, options)
|
1184
|
+
soap.tag! "ns1:overrideTransaction" do |soap|
|
1185
|
+
build_token soap, options
|
1186
|
+
build_tag soap, :integer, 'RefNum', options[:reference_number]
|
1187
|
+
build_tag soap, :string, 'Reason', options[:reason]
|
1188
|
+
end
|
1189
|
+
end
|
1190
|
+
|
1191
|
+
# Account =======================================================
|
1192
|
+
|
1193
|
+
def build_get_account_details(soap, options)
|
1194
|
+
soap.tag! "ns1:getAccountDetails" do |soap|
|
1195
|
+
build_token soap, options
|
1196
|
+
end
|
1197
|
+
end
|
1198
|
+
|
1199
|
+
# Customer Helpers ==============================================
|
1200
|
+
|
1201
|
+
def build_customer_data(soap, options)
|
1202
|
+
soap.CustomerData 'xsi:type' => 'ns1:CustomerObject' do
|
1203
|
+
CUSTOMER_OPTIONS.each do |k,v|
|
1204
|
+
build_tag soap, v[0], v[1], options[k]
|
1205
|
+
end
|
1206
|
+
build_billing_address soap, options
|
1207
|
+
build_customer_payments soap, options
|
1208
|
+
build_custom_fields soap, options
|
1209
|
+
end
|
1210
|
+
end
|
1211
|
+
|
1212
|
+
def build_customer_payments(soap, options)
|
1213
|
+
if options[:payment_methods]
|
1214
|
+
length = options[:payment_methods].length
|
1215
|
+
soap.PaymentMethods 'SOAP-ENC:arrayType' => "ns1:PaymentMethod[#{length}]",
|
1216
|
+
'xsi:type' =>"ns1:PaymentMethodArray" do |soap|
|
1217
|
+
build_customer_payment_methods soap, options
|
1218
|
+
end
|
1219
|
+
end
|
1220
|
+
end
|
1221
|
+
|
1222
|
+
def extract_methods_and_tag(options)
|
1223
|
+
case
|
1224
|
+
when options[:payment_method] && !options[:payment_methods]
|
1225
|
+
payment_methods = [options[:payment_method]]
|
1226
|
+
tag_name = 'PaymentMethod'
|
1227
|
+
when options[:payment_methods] && !options[:payment_method]
|
1228
|
+
payment_methods = options[:payment_methods]
|
1229
|
+
tag_name = 'item'
|
1230
|
+
else
|
1231
|
+
payment_methods = [options]
|
1232
|
+
tag_name = 'PaymentMethod'
|
1233
|
+
end
|
1234
|
+
[payment_methods, tag_name]
|
1235
|
+
end
|
1236
|
+
|
1237
|
+
def build_credit_card_or_check(soap, payment_method)
|
1238
|
+
case
|
1239
|
+
when payment_method[:method].kind_of?(ActiveMerchant::Billing::CreditCard)
|
1240
|
+
build_tag soap, :string, 'CardNumber', payment_method[:method].number
|
1241
|
+
build_tag soap, :string, 'CardExpiration',
|
1242
|
+
"#{payment_method[:method].year}-#{"%02d" % payment_method[:method].month}"
|
1243
|
+
if options[:billing_address]
|
1244
|
+
build_tag soap, :string, 'AvsStreet', options[:billing_address][:address1]
|
1245
|
+
build_tag soap, :string, 'AvsZip', options[:billing_address][:zip]
|
1246
|
+
end
|
1247
|
+
build_tag soap, :string, 'CardCode', payment_method[:method].verification_value
|
1248
|
+
when payment_method[:method].kind_of?(ActiveMerchant::Billing::Check)
|
1249
|
+
build_tag soap, :string, 'Account', payment_method[:method].number
|
1250
|
+
build_tag soap, :string, 'Routing', payment_method[:method].routing_number
|
1251
|
+
build_tag soap, :string, 'AccountType', payment_method[:method].account_type.capitalize
|
1252
|
+
build_tag soap, :string, 'DriversLicense', options[:drivers_license]
|
1253
|
+
build_tag soap, :string, 'DriversLicenseState', options[:drivers_license_state]
|
1254
|
+
build_tag soap, :string, 'RecordType', options[:record_type]
|
1255
|
+
end
|
1256
|
+
end
|
1257
|
+
|
1258
|
+
def build_customer_payment_methods(soap, options)
|
1259
|
+
payment_methods, tag_name = extract_methods_and_tag(options)
|
1260
|
+
payment_methods.each do |payment_method|
|
1261
|
+
soap.tag! tag_name, 'xsi:type' => "ns1:PaymentMethod" do |soap|
|
1262
|
+
build_tag soap, :integer, 'MethodID', payment_method[:method_id]
|
1263
|
+
build_tag soap, :string, 'MethodType', payment_method[:type]
|
1264
|
+
build_tag soap, :string, 'MethodName', payment_method[:name]
|
1265
|
+
build_tag soap, :integer, 'SecondarySort', payment_method[:sort]
|
1266
|
+
build_credit_card_or_check(soap, payment_method)
|
1267
|
+
end
|
1268
|
+
end
|
1269
|
+
end
|
1270
|
+
|
1271
|
+
def build_customer_transaction(soap, options)
|
1272
|
+
soap.Parameters 'xsi:type' => "ns1:CustomerTransactionRequest" do |soap|
|
1273
|
+
build_transaction_detail soap, options
|
1274
|
+
CUSTOMER_TRANSACTION_REQUEST_OPTIONS.each do |k,v|
|
1275
|
+
build_tag soap, v[0], v[1], options[k]
|
1276
|
+
end
|
1277
|
+
build_custom_fields soap, options
|
1278
|
+
build_line_items soap, options
|
1279
|
+
end
|
1280
|
+
end
|
1281
|
+
|
1282
|
+
# Transaction Helpers ===========================================
|
1283
|
+
|
1284
|
+
def build_transaction_request_object(soap, options, name='Params')
|
1285
|
+
soap.tag! name, 'xsi:type' => "ns1:TransactionRequestObject" do |soap|
|
1286
|
+
TRANSACTION_REQUEST_OBJECT_OPTIONS.each do |k,v|
|
1287
|
+
build_tag soap, v[0], v[1], options[k]
|
1288
|
+
end
|
1289
|
+
case
|
1290
|
+
when options[:payment_method] == nil
|
1291
|
+
when options[:payment_method].kind_of?(ActiveMerchant::Billing::CreditCard)
|
1292
|
+
build_credit_card_data soap, options
|
1293
|
+
when options[:payment_method].kind_of?(ActiveMerchant::Billing::Check)
|
1294
|
+
build_check_data soap, options
|
1295
|
+
else
|
1296
|
+
raise ArgumentError, 'options[:payment_method] must be a CreditCard or Check'
|
1297
|
+
end
|
1298
|
+
build_transaction_detail soap, options
|
1299
|
+
build_billing_address soap, options
|
1300
|
+
build_shipping_address soap, options
|
1301
|
+
build_recurring_billing soap, options
|
1302
|
+
build_line_items soap, options
|
1303
|
+
build_custom_fields soap, options
|
1304
|
+
end
|
1305
|
+
end
|
1306
|
+
|
1307
|
+
def build_transaction_detail(soap, options)
|
1308
|
+
soap.Details 'xsi:type' => "ns1:TransactionDetail" do |soap|
|
1309
|
+
TRANSACTION_DETAIL_OPTIONS.each do |k,v|
|
1310
|
+
build_tag soap, v[0], v[1], options[k]
|
1311
|
+
end
|
1312
|
+
TRANSACTION_DETAIL_MONEY_OPTIONS.each do |k,v|
|
1313
|
+
build_tag soap, v[0], v[1], amount(options[k])
|
1314
|
+
end
|
1315
|
+
end
|
1316
|
+
end
|
1317
|
+
|
1318
|
+
def build_credit_card_data(soap, options)
|
1319
|
+
soap.CreditCardData 'xsi:type' => "ns1:CreditCardData" do |soap|
|
1320
|
+
build_tag soap, :string, 'CardNumber', options[:payment_method].number
|
1321
|
+
build_tag soap, :string, 'CardExpiration',
|
1322
|
+
"#{options[:payment_method].year}-#{"%02d" % options[:payment_method].month}"
|
1323
|
+
if options[:billing_address]
|
1324
|
+
build_tag soap, :string, 'AvsStreet', options[:billing_address][:address1]
|
1325
|
+
build_tag soap, :string, 'AvsZip', options[:billing_address][:zip]
|
1326
|
+
end
|
1327
|
+
build_tag soap, :string, 'CardCode', options[:payment_method].verification_value
|
1328
|
+
build_tag soap, :boolean, 'CardPresent', options[:card_present] || false
|
1329
|
+
CREDIT_CARD_DATA_OPTIONS.each do |k,v|
|
1330
|
+
build_tag soap, v[0], v[1], options[k]
|
1331
|
+
end
|
1332
|
+
end
|
1333
|
+
end
|
1334
|
+
|
1335
|
+
def build_check_data(soap, options)
|
1336
|
+
soap.CheckData 'xsi:type' => "ns1:CheckData" do |soap|
|
1337
|
+
build_tag soap, :string, 'Account', options[:payment_method].number
|
1338
|
+
build_tag soap, :string, 'Routing', options[:payment_method].routing_number
|
1339
|
+
build_tag soap, :string, 'AccountType', options[:payment_method].account_type.capitalize
|
1340
|
+
CHECK_DATA_OPTIONS.each do |k,v|
|
1341
|
+
build_tag soap, v[0], v[1], options[k]
|
1342
|
+
end
|
1343
|
+
end
|
1344
|
+
end
|
1345
|
+
|
1346
|
+
def build_recurring_billing(soap, options)
|
1347
|
+
if options[:recurring]
|
1348
|
+
soap.RecurringBilling 'xsi:type' => "ns1:RecurringBilling" do |soap|
|
1349
|
+
build_tag soap, :double, 'Amount', amount(options[:recurring][:amount])
|
1350
|
+
build_tag soap, :string, 'Next', options[:recurring][:next].strftime("%Y-%m-%d") if options[:recurring][:next]
|
1351
|
+
build_tag soap, :string, 'Expire', options[:recurring][:expire].strftime("%Y-%m-%d") if options[:recurring][:expire]
|
1352
|
+
RECURRING_BILLING_OPTIONS.each do |k,v|
|
1353
|
+
build_tag soap, v[0], v[1], options[:recurring][k]
|
1354
|
+
end
|
1355
|
+
end
|
1356
|
+
end
|
1357
|
+
end
|
1358
|
+
|
1359
|
+
def build_transaction_field_array(soap, options)
|
1360
|
+
soap.Fields 'SOAP-ENC:arryType' => "xsd:string[#{options[:fields].length}]", 'xsi:type' => 'ns1:stringArray' do |soap|
|
1361
|
+
options[:fields].each do |field|
|
1362
|
+
build_tag soap, :string, 'item', field
|
1363
|
+
end
|
1364
|
+
end
|
1365
|
+
end
|
1366
|
+
|
1367
|
+
# General Helpers ===============================================
|
1368
|
+
|
1369
|
+
def build_billing_address(soap, options)
|
1370
|
+
if options[:billing_address]
|
1371
|
+
if options[:billing_address][:name]
|
1372
|
+
name = options[:billing_address][:name].split(nil,2) # divide name
|
1373
|
+
options[:billing_address][:first_name], options[:billing_address][:last_name] = name[0], name[1]
|
1374
|
+
end
|
1375
|
+
soap.BillingAddress 'xsi:type' => "ns1:Address" do
|
1376
|
+
ADDRESS_OPTIONS.each do |k,v|
|
1377
|
+
build_tag soap, v[0], v[1], options[:billing_address][k]
|
1378
|
+
end
|
1379
|
+
end
|
1380
|
+
end
|
1381
|
+
end
|
1382
|
+
|
1383
|
+
def build_shipping_address(soap, options)
|
1384
|
+
if options[:shipping_address]
|
1385
|
+
if options[:shipping_address][:name]
|
1386
|
+
name = options[:shipping_address][:name].split(nil,2) # divide name
|
1387
|
+
options[:shipping_address][:first_name], options[:shipping_address][:last_name] = name[0], name[1]
|
1388
|
+
end
|
1389
|
+
soap.ShippingAddress 'xsi:type' => "ns1:Address" do
|
1390
|
+
ADDRESS_OPTIONS.each do |k,v|
|
1391
|
+
build_tag soap, v[0], v[1], options[:shipping_address][k]
|
1392
|
+
end
|
1393
|
+
end
|
1394
|
+
end
|
1395
|
+
end
|
1396
|
+
|
1397
|
+
def build_line_items(soap, options) # TODO
|
1398
|
+
end
|
1399
|
+
|
1400
|
+
def build_custom_fields(soap, options) # TODO
|
1401
|
+
end
|
1402
|
+
|
1403
|
+
# Request =======================================================
|
1404
|
+
|
1405
|
+
def commit(action, request)
|
1406
|
+
url = test? ? test_url : live_url
|
1407
|
+
|
1408
|
+
begin
|
1409
|
+
soap = ssl_post(url, request, "Content-Type" => "text/xml")
|
1410
|
+
rescue ActiveMerchant::ResponseError => error
|
1411
|
+
soap = error.response.body
|
1412
|
+
end
|
1413
|
+
|
1414
|
+
response = build_response(action, soap)
|
1415
|
+
end
|
1416
|
+
|
1417
|
+
def build_response(action, soap)
|
1418
|
+
response_params, success, message, authorization, avs, cvv = parse(action, soap)
|
1419
|
+
|
1420
|
+
response_params.merge!('soap_response' => soap) if @options[:soap_response]
|
1421
|
+
|
1422
|
+
response = Response.new(
|
1423
|
+
success, message, response_params,
|
1424
|
+
:test => test?, :authorization => authorization,
|
1425
|
+
:avs_result => avs_from(avs),
|
1426
|
+
:cvv_result => cvv
|
1427
|
+
)
|
1428
|
+
end
|
1429
|
+
|
1430
|
+
def avs_from(avs)
|
1431
|
+
avs_params = { :code => avs }
|
1432
|
+
avs_params.merge!(:message => AVS_CUSTOM_MESSAGES[avs]) if AVS_CUSTOM_MESSAGES.key?(avs)
|
1433
|
+
avs_params
|
1434
|
+
end
|
1435
|
+
|
1436
|
+
def parse(action, soap)
|
1437
|
+
xml = REXML::Document.new(soap)
|
1438
|
+
root = REXML::XPath.first(xml, "//SOAP-ENV:Body")
|
1439
|
+
response = root ? parse_element(root[0]) : { :response => soap }
|
1440
|
+
|
1441
|
+
success, message, authorization, avs, cvv = false, FAILURE_MESSAGE, nil, nil, nil
|
1442
|
+
|
1443
|
+
fault = (!response) || (response.length < 1) || response.has_key?('faultcode')
|
1444
|
+
return [response, success, response['faultstring'], authorization, avs, cvv] if fault
|
1445
|
+
|
1446
|
+
if response.respond_to?(:[]) && p = response["#{action}_return"]
|
1447
|
+
if p.respond_to?(:key?) && p.key?('result_code')
|
1448
|
+
success = p['result_code'] == 'A' ? true : false
|
1449
|
+
authorization = p['ref_num']
|
1450
|
+
avs = AVS_RESULTS[p['avs_result_code']]
|
1451
|
+
cvv = p['card_code_result_code']
|
1452
|
+
else
|
1453
|
+
success = true
|
1454
|
+
end
|
1455
|
+
message = case action
|
1456
|
+
when :get_customer_payment_methods
|
1457
|
+
p['item']
|
1458
|
+
when :get_transaction_custom
|
1459
|
+
p['item'].inject({}) { |map, field| map[field['field']] = field['value']; map }
|
1460
|
+
else
|
1461
|
+
p
|
1462
|
+
end
|
1463
|
+
elsif response.respond_to?(:[]) && p = response[:response]
|
1464
|
+
message = p # when response is html
|
1465
|
+
end
|
1466
|
+
|
1467
|
+
[response, success, message, authorization, avs, cvv]
|
1468
|
+
end
|
1469
|
+
|
1470
|
+
def parse_element(node)
|
1471
|
+
if node.has_elements?
|
1472
|
+
response = {}
|
1473
|
+
node.elements.each do |e|
|
1474
|
+
key = e.name.underscore
|
1475
|
+
value = parse_element(e)
|
1476
|
+
if response.has_key?(key)
|
1477
|
+
if response[key].is_a?(Array)
|
1478
|
+
response[key].push(value)
|
1479
|
+
else
|
1480
|
+
response[key] = [response[key], value]
|
1481
|
+
end
|
1482
|
+
else
|
1483
|
+
response[key] = parse_element(e)
|
1484
|
+
end
|
1485
|
+
end
|
1486
|
+
else
|
1487
|
+
response = node.text
|
1488
|
+
end
|
1489
|
+
|
1490
|
+
response
|
1491
|
+
end
|
1492
|
+
|
1493
|
+
end
|
1494
|
+
end
|
1495
|
+
end
|
1496
|
+
|