activemerchant 1.20.4 → 1.21.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 +29 -0
- data/CONTRIBUTORS +13 -0
- data/lib/active_merchant/billing/credit_card_methods.rb +1 -1
- data/lib/active_merchant/billing/gateway.rb +1 -1
- data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +104 -18
- data/lib/active_merchant/billing/gateways/beanstream.rb +29 -1
- data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +105 -3
- data/lib/active_merchant/billing/gateways/braintree_orange.rb +4 -0
- data/lib/active_merchant/billing/gateways/certo_direct.rb +279 -0
- data/lib/active_merchant/billing/gateways/epay.rb +2 -2
- data/lib/active_merchant/billing/gateways/eway_managed.rb +1 -0
- data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +1 -0
- data/lib/active_merchant/billing/gateways/nab_transact.rb +244 -0
- data/lib/active_merchant/billing/gateways/payflow.rb +10 -2
- data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +1 -0
- data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +1 -1
- data/lib/active_merchant/billing/gateways/paypal_digital_goods.rb +43 -0
- data/lib/active_merchant/billing/gateways/paypal_express.rb +36 -1
- data/lib/active_merchant/billing/gateways/paypal_express_common.rb +8 -3
- data/lib/active_merchant/billing/gateways/quickpay.rb +1 -0
- data/lib/active_merchant/billing/gateways/samurai.rb +1 -0
- data/lib/active_merchant/billing/gateways/secure_pay_au.rb +136 -49
- data/lib/active_merchant/billing/gateways/secure_pay_tech.rb +1 -1
- data/lib/active_merchant/billing/gateways/stripe.rb +23 -11
- data/lib/active_merchant/billing/gateways/verifi.rb +2 -2
- data/lib/active_merchant/billing/gateways/viaklix.rb +1 -1
- data/lib/active_merchant/billing/integrations/action_view_helper.rb +5 -1
- data/lib/active_merchant/billing/integrations/authorize_net_sim.rb +38 -0
- data/lib/active_merchant/billing/integrations/authorize_net_sim/helper.rb +228 -0
- data/lib/active_merchant/billing/integrations/authorize_net_sim/notification.rb +340 -0
- data/lib/active_merchant/billing/integrations/helper.rb +13 -1
- data/lib/active_merchant/billing/integrations/payflow_link/helper.rb +1 -1
- data/lib/active_merchant/version.rb +1 -1
- metadata +37 -31
- metadata.gz.sig +0 -0
@@ -11,6 +11,10 @@ module ActiveMerchant #:nodoc:
|
|
11
11
|
def api_url
|
12
12
|
'https://secure.braintreepaymentgateway.com/api/transact.php'
|
13
13
|
end
|
14
|
+
|
15
|
+
def add_processor(post, options)
|
16
|
+
post[:processor_id] = options[:processor] unless options[:processor].nil?
|
17
|
+
end
|
14
18
|
end
|
15
19
|
end
|
16
20
|
end
|
@@ -0,0 +1,279 @@
|
|
1
|
+
module ActiveMerchant #:nodoc:
|
2
|
+
module Billing #:nodoc:
|
3
|
+
class CertoDirectGateway < Gateway
|
4
|
+
class_attribute :gateway_url
|
5
|
+
self.gateway_url = "https://secure.certodirect.com/gateway/process/v2"
|
6
|
+
|
7
|
+
self.supported_countries = [
|
8
|
+
"BE", "BG", "CZ", "DK", "DE", "EE", "IE", "EL", "ES", "FR",
|
9
|
+
"IT", "CY", "LV", "LT", "LU", "HU", "MT", "NL", "AT", "PL",
|
10
|
+
"PT", "RO", "SI", "SK", "FI", "SE", "UK"
|
11
|
+
]
|
12
|
+
|
13
|
+
self.supported_cardtypes = [:visa, :master, :american_express, :discover]
|
14
|
+
self.homepage_url = 'http://www.certodirect.com/'
|
15
|
+
self.display_name = 'CertoDirect'
|
16
|
+
|
17
|
+
# Creates a new CertoDirectGateway
|
18
|
+
#
|
19
|
+
# The gateway requires that a valid login and password be passed
|
20
|
+
# in the +options+ hash.
|
21
|
+
#
|
22
|
+
# ==== Options
|
23
|
+
#
|
24
|
+
# * <tt>:login</tt> -- The CertoDirect Shop ID (REQUIRED)
|
25
|
+
# * <tt>:password</tt> -- The CertoDirect Shop Password. (REQUIRED)
|
26
|
+
# * <tt>:test</tt> -- +true+ or +false+. If true, perform transactions against the test server.
|
27
|
+
# Otherwise, perform transactions against the production server.
|
28
|
+
def initialize(options = {})
|
29
|
+
requires!(options, :login, :password)
|
30
|
+
@options = options
|
31
|
+
super
|
32
|
+
end
|
33
|
+
|
34
|
+
# Perform a purchase, which is essentially an authorization and capture in a single operation.
|
35
|
+
#
|
36
|
+
# ==== Parameters
|
37
|
+
#
|
38
|
+
# * <tt>money</tt> -- The amount to be purchased as an Integer value in cents.
|
39
|
+
# * <tt>credit_card</tt> -- The CreditCard details for the transaction.
|
40
|
+
# * <tt>options</tt> -- A hash of optional parameters.
|
41
|
+
def purchase(money, credit_card, options = {})
|
42
|
+
requires!(options, :email, :currency, :ip, :description)
|
43
|
+
|
44
|
+
commit(build_sale_request(money, credit_card, options))
|
45
|
+
end
|
46
|
+
|
47
|
+
# Refund a transaction.
|
48
|
+
#
|
49
|
+
# This transaction indicates to the gateway that
|
50
|
+
# money should flow from the merchant to the customer.
|
51
|
+
#
|
52
|
+
# ==== Parameters
|
53
|
+
#
|
54
|
+
# * <tt>money</tt> -- The amount to be credited to the customer as an Integer value in cents.
|
55
|
+
# * <tt>identification</tt> -- The ID of the original order against which the refund is being issued.
|
56
|
+
# * <tt>options</tt> -- A hash of parameters.
|
57
|
+
def refund(money, identification, options = {})
|
58
|
+
requires!(options, :reason)
|
59
|
+
|
60
|
+
commit(build_refund_request(money, identification, options))
|
61
|
+
end
|
62
|
+
|
63
|
+
# Performs an authorization, which reserves the funds on the customer's credit card, but does not
|
64
|
+
# charge the card.
|
65
|
+
#
|
66
|
+
# ==== Parameters
|
67
|
+
#
|
68
|
+
# * <tt>money</tt> -- The amount to be authorized as an Integer value in cents.
|
69
|
+
# * <tt>credit_card</tt> -- The CreditCard details for the transaction.
|
70
|
+
# * <tt>options</tt> -- A hash of optional parameters.
|
71
|
+
def authorize(money, credit_card, options = {})
|
72
|
+
requires!(options, :email, :currency, :ip, :description)
|
73
|
+
|
74
|
+
commit(build_authorize_request(money, credit_card, options))
|
75
|
+
end
|
76
|
+
|
77
|
+
# Captures the funds from an authorized transaction.
|
78
|
+
#
|
79
|
+
# ==== Parameters
|
80
|
+
#
|
81
|
+
# * <tt>money</tt> -- The amount to be captured as an Integer value in cents.
|
82
|
+
# * <tt>identification</tt> -- The authorization returned from the previous authorize request.
|
83
|
+
def capture(money, identification, options = {})
|
84
|
+
commit(build_capture_request(money, identification))
|
85
|
+
end
|
86
|
+
|
87
|
+
# Void a previous transaction
|
88
|
+
#
|
89
|
+
# ==== Parameters
|
90
|
+
#
|
91
|
+
# * <tt>money</tt> -- The amount to be captured as an Integer value in cents.
|
92
|
+
# * <tt>identification</tt> - The authorization returned from the previous authorize request.
|
93
|
+
def void(money, identification, options = {})
|
94
|
+
commit(build_void_request(money, identification))
|
95
|
+
end
|
96
|
+
|
97
|
+
# Create a recurring payment.
|
98
|
+
#
|
99
|
+
# ==== Parameters
|
100
|
+
#
|
101
|
+
# * <tt>options</tt> -- A hash of parameters.
|
102
|
+
#
|
103
|
+
# ==== Options
|
104
|
+
#
|
105
|
+
def recurring(identification, options={})
|
106
|
+
commit(build_recurring_request(identification, options))
|
107
|
+
end
|
108
|
+
|
109
|
+
|
110
|
+
private
|
111
|
+
|
112
|
+
def commit(request_xml)
|
113
|
+
begin
|
114
|
+
response = Hash.from_xml(ssl_post(gateway_url, request_xml, headers))
|
115
|
+
Response.new(success?(response),
|
116
|
+
message(response),
|
117
|
+
response,
|
118
|
+
:test => test?,
|
119
|
+
:authorization => authorization(response))
|
120
|
+
rescue ResponseError => e
|
121
|
+
raise e unless e.response.code == '403'
|
122
|
+
response = Hash.from_xml(e.response.body)['response']
|
123
|
+
Response.new(false, message(response), {}, :test => test?)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def build_sale_request(money, credit_card, options)
|
128
|
+
build_request_xml('Sale') do |xml|
|
129
|
+
add_order(xml, money, credit_card, options)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def build_authorize_request(money, credit_card, options)
|
134
|
+
build_request_xml('Authorize') do |xml|
|
135
|
+
add_order(xml, money, credit_card, options)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def build_refund_request(money, identification, options)
|
140
|
+
build_request_xml('Refund') do |xml|
|
141
|
+
add_reference_info(xml, money, identification, options)
|
142
|
+
xml.tag! 'reason', options[:reason]
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def build_capture_request(money, identification)
|
147
|
+
build_request_xml('Capture') do |xml|
|
148
|
+
add_reference_info(xml, money, identification, options)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def build_void_request(money, identification)
|
153
|
+
build_request_xml('Void') do |xml|
|
154
|
+
add_reference_info(xml, money, identification, options)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def build_recurring_request(identification, options)
|
159
|
+
build_request_xml('Sale') do |xml|
|
160
|
+
xml.tag! 'order' do |xml|
|
161
|
+
xml.tag!('test', 'true') if test?
|
162
|
+
xml.tag! 'initial_order_id', identification, :type => 'integer'
|
163
|
+
|
164
|
+
add_order_details(xml, options[:amount], options) if has_any_order_details_key?(options)
|
165
|
+
add_address(xml, 'billing_address', options[:billing_address]) if options[:billing_address]
|
166
|
+
add_address(xml, 'shipping_address', options[:shipping_address]) if options[:shipping_address]
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def build_request_xml(type, &block)
|
172
|
+
xml = Builder::XmlMarkup.new(:indent => 2)
|
173
|
+
xml.tag! 'transaction' do
|
174
|
+
xml.tag! 'type', type
|
175
|
+
yield(xml)
|
176
|
+
end
|
177
|
+
xml.target!
|
178
|
+
end
|
179
|
+
|
180
|
+
def add_order(xml, money, credit_card, options)
|
181
|
+
xml.tag! 'order' do
|
182
|
+
xml.tag!('test', 'true') if test?
|
183
|
+
|
184
|
+
xml.tag!('return_url', options[:return_url]) if options[:return_url]
|
185
|
+
xml.tag!('cancel_url', options[:cancel_url]) if options[:cancel_url]
|
186
|
+
|
187
|
+
xml.tag! 'payment_method_type', 'CreditCard'
|
188
|
+
xml.tag! 'payment_method' do
|
189
|
+
xml.tag! 'number', credit_card.number
|
190
|
+
xml.tag! 'exp_month', "%02i" % credit_card.month
|
191
|
+
xml.tag! 'exp_year', credit_card.year
|
192
|
+
xml.tag! 'holder', credit_card.name
|
193
|
+
xml.tag! 'verification_value', credit_card.verification_value
|
194
|
+
end
|
195
|
+
|
196
|
+
add_order_details(xml, money, options)
|
197
|
+
add_address(xml, 'billing_address', options[:billing_address]) if options[:billing_address]
|
198
|
+
add_address(xml, 'shipping_address', options[:shipping_address]) if options[:shipping_address]
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
def add_order_details(xml, money, options)
|
203
|
+
xml.tag! 'details' do
|
204
|
+
xml.tag!('amount', localized_amount(money, options[:currency]), :type => 'decimal') if money
|
205
|
+
xml.tag!('currency', options[:currency]) if options[:currency]
|
206
|
+
xml.tag!('email', options[:email]) if options[:email]
|
207
|
+
xml.tag!('ip', options[:ip]) if options[:ip]
|
208
|
+
xml.tag!('shipping', options[:shipping], :type => 'decimal') if options[:shipping]
|
209
|
+
xml.tag!('description', options[:description]) if options[:description]
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
def add_reference_info(xml, money, identification, options)
|
214
|
+
xml.tag! 'order_id', identification, :type => 'integer'
|
215
|
+
xml.tag! 'amount', localized_amount(money, options[:currency]), :type => 'decimal'
|
216
|
+
end
|
217
|
+
|
218
|
+
def add_address(xml, address_type, address)
|
219
|
+
xml.tag! address_type do
|
220
|
+
xml.tag! 'address', address[:address1]
|
221
|
+
xml.tag! 'city', address[:city]
|
222
|
+
xml.tag! 'country', address[:country]
|
223
|
+
xml.tag! 'first_name', address[:first_name]
|
224
|
+
xml.tag! 'last_name', address[:last_name]
|
225
|
+
xml.tag! 'state', address[:state]
|
226
|
+
xml.tag! 'phone', address[:phone]
|
227
|
+
xml.tag! 'zip', address[:zip]
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
def has_any_order_details_key?(options)
|
232
|
+
[ :currency, :amount, :email, :ip, :shipping, :description ].any? do |key|
|
233
|
+
options.has_key?(key)
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
def success?(response)
|
238
|
+
%w(completed forwarding).include?(state(response)) and
|
239
|
+
status(response) == 'success'
|
240
|
+
end
|
241
|
+
|
242
|
+
def error?(response)
|
243
|
+
response['errors']
|
244
|
+
end
|
245
|
+
|
246
|
+
def state(response)
|
247
|
+
response["transaction"].try(:[], "state")
|
248
|
+
end
|
249
|
+
|
250
|
+
def status(response)
|
251
|
+
response['transaction'].try(:[], 'response').try(:[], 'status')
|
252
|
+
end
|
253
|
+
|
254
|
+
def authorization(response)
|
255
|
+
error?(response) ? nil : response["transaction"]["order"]['id'].to_s
|
256
|
+
end
|
257
|
+
|
258
|
+
def message(response)
|
259
|
+
return response['errors'].join('; ') if error?(response)
|
260
|
+
|
261
|
+
if state(response) == 'completed'
|
262
|
+
response["transaction"]["response"]["message"]
|
263
|
+
else
|
264
|
+
response['transaction']['message']
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
def headers
|
269
|
+
{ 'authorization' => basic_auth,
|
270
|
+
'Accept' => 'application/xml',
|
271
|
+
'Content-Type' => 'application/xml' }
|
272
|
+
end
|
273
|
+
|
274
|
+
def basic_auth
|
275
|
+
'Basic ' + ["#{@options[:login]}:#{@options[:password]}"].pack('m').delete("\r\n")
|
276
|
+
end
|
277
|
+
end
|
278
|
+
end
|
279
|
+
end
|
@@ -53,7 +53,7 @@ module ActiveMerchant #:nodoc:
|
|
53
53
|
# login: merchant number
|
54
54
|
# password: referrer url (for authorize authentication)
|
55
55
|
def initialize(options = {})
|
56
|
-
requires!(options, :login
|
56
|
+
requires!(options, :login)
|
57
57
|
@options = options
|
58
58
|
super
|
59
59
|
end
|
@@ -181,7 +181,7 @@ module ActiveMerchant #:nodoc:
|
|
181
181
|
|
182
182
|
def do_authorize(params)
|
183
183
|
headers = {}
|
184
|
-
headers['Referer'] = options[:password]
|
184
|
+
headers['Referer'] = (options[:password] || "activemerchant.org")
|
185
185
|
|
186
186
|
response = raw_ssl_request(:post, 'https://' + API_HOST + '/auth/default.aspx', authorize_post_data(params), headers)
|
187
187
|
|
@@ -188,6 +188,7 @@ private
|
|
188
188
|
reply[:message]=REXML::XPath.first(node, '//ewayTrxnError').text
|
189
189
|
reply[:success]=(REXML::XPath.first(node, '//ewayTrxnStatus').text == 'True')
|
190
190
|
reply[:auth_code]=REXML::XPath.first(node, '//ewayAuthCode').text
|
191
|
+
reply[:transaction_number]=REXML::XPath.first(node, '//ewayTrxnNumber').text
|
191
192
|
reply
|
192
193
|
end
|
193
194
|
|
@@ -90,6 +90,7 @@ module ActiveMerchant #:nodoc:
|
|
90
90
|
if creditcard_or_card_id.is_a?(String)
|
91
91
|
# using stored card
|
92
92
|
post[:card_id] = creditcard_or_card_id
|
93
|
+
post[:card_exp_date] = options[:expiration_date] if options[:expiration_date]
|
93
94
|
else
|
94
95
|
# card info is provided
|
95
96
|
add_creditcard(post, creditcard_or_card_id, options)
|
@@ -0,0 +1,244 @@
|
|
1
|
+
require 'rexml/document'
|
2
|
+
|
3
|
+
module ActiveMerchant #:nodoc:
|
4
|
+
module Billing #:nodoc:
|
5
|
+
# The National Australia Bank provide a payment gateway that seems to
|
6
|
+
# be a rebadged Securepay Australia service, though some differences exist.
|
7
|
+
class NabTransactGateway < Gateway
|
8
|
+
API_VERSION = 'xml-4.2'
|
9
|
+
PERIODIC_API_VERSION = "spxml-4.2"
|
10
|
+
|
11
|
+
TEST_URL = 'https://transact.nab.com.au/test/xmlapi/payment'
|
12
|
+
LIVE_URL = 'https://transact.nab.com.au/live/xmlapi/payment'
|
13
|
+
TEST_PERIODIC_URL = "https://transact.nab.com.au/xmlapidemo/periodic"
|
14
|
+
LIVE_PERIODIC_URL = "https://transact.nab.com.au/xmlapi/periodic"
|
15
|
+
|
16
|
+
self.supported_countries = ['AU']
|
17
|
+
|
18
|
+
# The card types supported by the payment gateway
|
19
|
+
# Note that support for Diners, Amex, and JCB require extra
|
20
|
+
# steps in setting up your account, as detailed in the NAB Transact API
|
21
|
+
self.supported_cardtypes = [:visa, :master, :american_express, :diners_club, :jcb]
|
22
|
+
|
23
|
+
self.homepage_url = 'http://transact.nab.com.au'
|
24
|
+
self.display_name = 'NAB Transact'
|
25
|
+
|
26
|
+
cattr_accessor :request_timeout
|
27
|
+
self.request_timeout = 60
|
28
|
+
|
29
|
+
self.money_format = :cents
|
30
|
+
self.default_currency = 'AUD'
|
31
|
+
|
32
|
+
#Transactions currently accepted by NAB Transact XML API
|
33
|
+
TRANSACTIONS = {
|
34
|
+
:purchase => 0, #Standard Payment
|
35
|
+
:credit => 4, #Refund
|
36
|
+
:void => 6, #Client Reversal (Void)
|
37
|
+
:authorization => 10, #Preauthorise
|
38
|
+
:capture => 11 #Preauthorise Complete (Advice)
|
39
|
+
}
|
40
|
+
|
41
|
+
PERIODIC_TYPES = {
|
42
|
+
:addcrn => 5,
|
43
|
+
:editcrn => 5,
|
44
|
+
:deletecrn => 5,
|
45
|
+
:trigger => 8
|
46
|
+
}
|
47
|
+
|
48
|
+
SUCCESS_CODES = [ '00', '08', '11', '16', '77' ]
|
49
|
+
|
50
|
+
|
51
|
+
def initialize(options = {})
|
52
|
+
requires!(options, :login, :password)
|
53
|
+
@options = options
|
54
|
+
super
|
55
|
+
end
|
56
|
+
|
57
|
+
def test?
|
58
|
+
@options[:test] || super
|
59
|
+
end
|
60
|
+
|
61
|
+
def purchase(money, credit_card_or_stored_id, options = {})
|
62
|
+
if credit_card_or_stored_id.is_a?(ActiveMerchant::Billing::CreditCard)
|
63
|
+
#Credit card for instant payment
|
64
|
+
commit :purchase, build_purchase_request(money, credit_card_or_stored_id, options)
|
65
|
+
else
|
66
|
+
#Triggered payment for an existing stored credit card
|
67
|
+
options[:billing_id] = credit_card_or_stored_id.to_s
|
68
|
+
commit_periodic build_periodic_item(:trigger, money, nil, options)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def store(creditcard, options = {})
|
73
|
+
requires!(options, :billing_id, :amount)
|
74
|
+
commit_periodic(build_periodic_item(:addcrn, options[:amount], creditcard, options))
|
75
|
+
end
|
76
|
+
|
77
|
+
def unstore(identification, options = {})
|
78
|
+
options[:billing_id] = identification
|
79
|
+
commit_periodic(build_periodic_item(:deletecrn, options[:amount], nil, options))
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
def build_purchase_request(money, credit_card, options)
|
85
|
+
xml = Builder::XmlMarkup.new
|
86
|
+
xml.tag! 'amount', amount(money)
|
87
|
+
xml.tag! 'currency', options[:currency] || currency(money)
|
88
|
+
xml.tag! 'purchaseOrderNo', options[:order_id].to_s.gsub(/[ ']/, '')
|
89
|
+
|
90
|
+
xml.tag! 'CreditCardInfo' do
|
91
|
+
xml.tag! 'cardNumber', credit_card.number
|
92
|
+
xml.tag! 'expiryDate', expdate(credit_card)
|
93
|
+
xml.tag! 'cvv', credit_card.verification_value if credit_card.verification_value?
|
94
|
+
end
|
95
|
+
|
96
|
+
xml.target!
|
97
|
+
end
|
98
|
+
|
99
|
+
#Generate payment request XML
|
100
|
+
# - API is set to allow multiple Txn's but currentlu only allows one
|
101
|
+
# - txnSource = 23 - (XML)
|
102
|
+
|
103
|
+
def build_request(action, body)
|
104
|
+
xml = Builder::XmlMarkup.new
|
105
|
+
xml.instruct!
|
106
|
+
xml.tag! 'NABTransactMessage' do
|
107
|
+
xml.tag! 'MessageInfo' do
|
108
|
+
xml.tag! 'messageID', Utils.generate_unique_id.slice(0, 30)
|
109
|
+
xml.tag! 'messageTimestamp', generate_timestamp
|
110
|
+
xml.tag! 'timeoutValue', request_timeout
|
111
|
+
xml.tag! 'apiVersion', API_VERSION
|
112
|
+
end
|
113
|
+
|
114
|
+
xml.tag! 'MerchantInfo' do
|
115
|
+
xml.tag! 'merchantID', @options[:login]
|
116
|
+
xml.tag! 'password', @options[:password]
|
117
|
+
end
|
118
|
+
|
119
|
+
xml.tag! 'RequestType', 'Payment'
|
120
|
+
xml.tag! 'Payment' do
|
121
|
+
xml.tag! 'TxnList', "count" => 1 do
|
122
|
+
xml.tag! 'Txn', "ID" => 1 do
|
123
|
+
xml.tag! 'txnType', TRANSACTIONS[action]
|
124
|
+
xml.tag! 'txnSource', 23
|
125
|
+
xml << body
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
xml.target!
|
132
|
+
end
|
133
|
+
|
134
|
+
def build_periodic_item(action, money, credit_card, options)
|
135
|
+
xml = Builder::XmlMarkup.new
|
136
|
+
|
137
|
+
xml.tag! 'actionType', action.to_s
|
138
|
+
xml.tag! 'periodicType', PERIODIC_TYPES[action] if PERIODIC_TYPES[action]
|
139
|
+
xml.tag! 'currency', options[:currency] || currency(money)
|
140
|
+
xml.tag! 'crn', options[:billing_id]
|
141
|
+
|
142
|
+
if credit_card
|
143
|
+
xml.tag! 'CreditCardInfo' do
|
144
|
+
xml.tag! 'cardNumber', credit_card.number
|
145
|
+
xml.tag! 'expiryDate', expdate(credit_card)
|
146
|
+
xml.tag! 'cvv', credit_card.verification_value if credit_card.verification_value?
|
147
|
+
end
|
148
|
+
end
|
149
|
+
xml.tag! 'amount', amount(money)
|
150
|
+
|
151
|
+
xml.target!
|
152
|
+
end
|
153
|
+
|
154
|
+
def build_periodic_request(body)
|
155
|
+
xml = Builder::XmlMarkup.new
|
156
|
+
xml.instruct!
|
157
|
+
xml.tag! 'NABTransactMessage' do
|
158
|
+
xml.tag! 'MessageInfo' do
|
159
|
+
xml.tag! 'messageID', ActiveMerchant::Utils.generate_unique_id.slice(0, 30)
|
160
|
+
xml.tag! 'messageTimestamp', generate_timestamp
|
161
|
+
xml.tag! 'timeoutValue', request_timeout
|
162
|
+
xml.tag! 'apiVersion', PERIODIC_API_VERSION
|
163
|
+
end
|
164
|
+
|
165
|
+
xml.tag! 'MerchantInfo' do
|
166
|
+
xml.tag! 'merchantID', @options[:login]
|
167
|
+
xml.tag! 'password', @options[:password]
|
168
|
+
end
|
169
|
+
|
170
|
+
xml.tag! 'RequestType', 'Periodic'
|
171
|
+
xml.tag! 'Periodic' do
|
172
|
+
xml.tag! 'PeriodicList', "count" => 1 do
|
173
|
+
xml.tag! 'PeriodicItem', "ID" => 1 do
|
174
|
+
xml << body
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
xml.target!
|
181
|
+
end
|
182
|
+
|
183
|
+
def commit(action, request)
|
184
|
+
response = parse(ssl_post(test? ? TEST_URL : LIVE_URL, build_request(action, request)))
|
185
|
+
|
186
|
+
Response.new(success?(response), message_from(response), response,
|
187
|
+
:test => test?,
|
188
|
+
:authorization => authorization_from(response)
|
189
|
+
)
|
190
|
+
end
|
191
|
+
|
192
|
+
def commit_periodic(request)
|
193
|
+
response = parse(ssl_post(test? ? TEST_PERIODIC_URL : LIVE_PERIODIC_URL, build_periodic_request(request)))
|
194
|
+
Response.new(success?(response), message_from(response), response,
|
195
|
+
:test => test?,
|
196
|
+
:authorization => authorization_from(response)
|
197
|
+
)
|
198
|
+
end
|
199
|
+
|
200
|
+
def success?(response)
|
201
|
+
SUCCESS_CODES.include?(response[:response_code])
|
202
|
+
end
|
203
|
+
|
204
|
+
def authorization_from(response)
|
205
|
+
response[:txn_id]
|
206
|
+
end
|
207
|
+
|
208
|
+
def message_from(response)
|
209
|
+
response[:response_text] || response[:status_description]
|
210
|
+
end
|
211
|
+
|
212
|
+
def expdate(credit_card)
|
213
|
+
"#{format(credit_card.month, :two_digits)}/#{format(credit_card.year, :two_digits)}"
|
214
|
+
end
|
215
|
+
|
216
|
+
def parse(body)
|
217
|
+
xml = REXML::Document.new(body)
|
218
|
+
|
219
|
+
response = {}
|
220
|
+
|
221
|
+
xml.root.elements.to_a.each do |node|
|
222
|
+
parse_element(response, node)
|
223
|
+
end
|
224
|
+
|
225
|
+
response
|
226
|
+
end
|
227
|
+
|
228
|
+
def parse_element(response, node)
|
229
|
+
if node.has_elements?
|
230
|
+
node.elements.each{|element| parse_element(response, element) }
|
231
|
+
else
|
232
|
+
response[node.name.underscore.to_sym] = node.text
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
# YYYYDDMMHHNNSSKKK000sOOO
|
237
|
+
def generate_timestamp
|
238
|
+
time = Time.now.utc
|
239
|
+
time.strftime("%Y%d%m%H%M%S#{time.usec}+000")
|
240
|
+
end
|
241
|
+
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|