activemerchant 1.29.1 → 1.31.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/CHANGELOG +58 -0
- data/CONTRIBUTORS +27 -0
- data/README.md +45 -41
- data/lib/active_merchant/billing/check.rb +11 -11
- data/lib/active_merchant/billing/credit_card.rb +1 -1
- data/lib/active_merchant/billing/credit_card_formatting.rb +8 -8
- data/lib/active_merchant/billing/gateway.rb +2 -2
- data/lib/active_merchant/billing/gateways/authorize_net.rb +9 -1
- data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +15 -4
- data/lib/active_merchant/billing/gateways/balanced.rb +9 -3
- data/lib/active_merchant/billing/gateways/banwire.rb +15 -1
- data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +6 -2
- data/lib/active_merchant/billing/gateways/beanstream.rb +26 -24
- data/lib/active_merchant/billing/gateways/braintree_blue.rb +5 -2
- data/lib/active_merchant/billing/gateways/cyber_source.rb +55 -22
- data/lib/active_merchant/billing/gateways/evo_ca.rb +308 -0
- data/lib/active_merchant/billing/gateways/eway.rb +114 -171
- data/lib/active_merchant/billing/gateways/eway_managed.rb +52 -22
- data/lib/active_merchant/billing/gateways/firstdata_e4.rb +232 -0
- data/lib/active_merchant/billing/gateways/ideal_rabobank.rb +13 -2
- data/lib/active_merchant/billing/gateways/litle.rb +50 -19
- data/lib/active_merchant/billing/gateways/merchant_ware.rb +44 -9
- data/lib/active_merchant/billing/gateways/merchant_warrior.rb +190 -0
- data/lib/active_merchant/billing/gateways/moneris.rb +3 -5
- data/lib/active_merchant/billing/gateways/moneris_us.rb +1 -1
- data/lib/active_merchant/billing/gateways/nab_transact.rb +20 -3
- data/lib/active_merchant/billing/gateways/netbilling.rb +1 -0
- data/lib/active_merchant/billing/gateways/netpay.rb +223 -0
- data/lib/active_merchant/billing/gateways/ogone.rb +6 -4
- data/lib/active_merchant/billing/gateways/optimal_payment.rb +18 -3
- data/lib/active_merchant/billing/gateways/orbital.rb +9 -5
- data/lib/active_merchant/billing/gateways/payment_express.rb +62 -1
- data/lib/active_merchant/billing/gateways/paymill.rb +161 -0
- data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +1 -1
- data/lib/active_merchant/billing/gateways/paypal_express.rb +17 -11
- data/lib/active_merchant/billing/gateways/pin.rb +157 -0
- data/lib/active_merchant/billing/gateways/qbms.rb +3 -2
- data/lib/active_merchant/billing/gateways/quickpay.rb +66 -28
- data/lib/active_merchant/billing/gateways/sage_pay.rb +6 -0
- data/lib/active_merchant/billing/gateways/smart_ps.rb +1 -1
- data/lib/active_merchant/billing/gateways/spreedly_core.rb +235 -0
- data/lib/active_merchant/billing/gateways/stripe.rb +1 -0
- data/lib/active_merchant/billing/gateways/wirecard.rb +15 -9
- data/lib/active_merchant/billing/gateways/worldpay.rb +19 -5
- data/lib/active_merchant/billing/integrations/payflow_link/helper.rb +4 -1
- data/lib/active_merchant/billing/integrations/paypal/notification.rb +39 -31
- data/lib/active_merchant/billing/integrations/quickpay/helper.rb +13 -10
- data/lib/active_merchant/billing/integrations/quickpay/notification.rb +14 -14
- data/lib/active_merchant/billing/integrations/sage_pay_form/helper.rb +2 -2
- data/lib/active_merchant/version.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +32 -24
- metadata.gz.sig +0 -0
|
@@ -22,7 +22,7 @@ module ActiveMerchant #:nodoc:
|
|
|
22
22
|
# password is your API Token
|
|
23
23
|
def initialize(options = {})
|
|
24
24
|
requires!(options, :login, :password)
|
|
25
|
-
|
|
25
|
+
options = { :crypt_type => 7 }.merge(options)
|
|
26
26
|
super
|
|
27
27
|
end
|
|
28
28
|
|
|
@@ -70,15 +70,13 @@ module ActiveMerchant #:nodoc:
|
|
|
70
70
|
commit 'completion', crediting_params(authorization, :comp_amount => amount(money))
|
|
71
71
|
end
|
|
72
72
|
|
|
73
|
-
# Voiding
|
|
74
|
-
# transaction. Closed transactions must be refunded. Note that the only
|
|
75
|
-
# methods which may be voided are +capture+ and +purchase+.
|
|
73
|
+
# Voiding cancels an open authorization.
|
|
76
74
|
#
|
|
77
75
|
# Concatenate your transaction number and order_id by using a semicolon
|
|
78
76
|
# (';'). This is to keep the Moneris interface consistent with other
|
|
79
77
|
# gateways. (See +capture+ for details.)
|
|
80
78
|
def void(authorization, options = {})
|
|
81
|
-
|
|
79
|
+
capture(0, authorization, options)
|
|
82
80
|
end
|
|
83
81
|
|
|
84
82
|
# Performs a refund. This method requires that the original transaction
|
|
@@ -34,7 +34,7 @@ module ActiveMerchant #:nodoc:
|
|
|
34
34
|
#Transactions currently accepted by NAB Transact XML API
|
|
35
35
|
TRANSACTIONS = {
|
|
36
36
|
:purchase => 0, #Standard Payment
|
|
37
|
-
:
|
|
37
|
+
:refund => 4, #Refund
|
|
38
38
|
:void => 6, #Client Reversal (Void)
|
|
39
39
|
:authorization => 10, #Preauthorise
|
|
40
40
|
:capture => 11 #Preauthorise Complete (Advice)
|
|
@@ -66,6 +66,10 @@ module ActiveMerchant #:nodoc:
|
|
|
66
66
|
end
|
|
67
67
|
end
|
|
68
68
|
|
|
69
|
+
def refund(money, authorization, options = {})
|
|
70
|
+
commit :refund, build_reference_request(money, authorization)
|
|
71
|
+
end
|
|
72
|
+
|
|
69
73
|
def store(creditcard, options = {})
|
|
70
74
|
requires!(options, :billing_id, :amount)
|
|
71
75
|
commit_periodic(build_periodic_item(:addcrn, options[:amount], creditcard, options))
|
|
@@ -104,10 +108,23 @@ module ActiveMerchant #:nodoc:
|
|
|
104
108
|
xml.target!
|
|
105
109
|
end
|
|
106
110
|
|
|
111
|
+
def build_reference_request(money, reference)
|
|
112
|
+
xml = Builder::XmlMarkup.new
|
|
113
|
+
|
|
114
|
+
transaction_id, order_id, preauth_id, original_amount = reference.split('*')
|
|
115
|
+
|
|
116
|
+
xml.tag! 'amount', (money ? amount(money) : original_amount)
|
|
117
|
+
xml.tag! 'currency', options[:currency] || currency(money)
|
|
118
|
+
xml.tag! 'txnID', transaction_id
|
|
119
|
+
xml.tag! 'purchaseOrderNo', order_id
|
|
120
|
+
xml.tag! 'preauthID', preauth_id
|
|
121
|
+
|
|
122
|
+
xml.target!
|
|
123
|
+
end
|
|
124
|
+
|
|
107
125
|
#Generate payment request XML
|
|
108
126
|
# - API is set to allow multiple Txn's but currentlu only allows one
|
|
109
127
|
# - txnSource = 23 - (XML)
|
|
110
|
-
|
|
111
128
|
def build_request(action, body)
|
|
112
129
|
xml = Builder::XmlMarkup.new
|
|
113
130
|
xml.instruct!
|
|
@@ -210,7 +227,7 @@ module ActiveMerchant #:nodoc:
|
|
|
210
227
|
end
|
|
211
228
|
|
|
212
229
|
def authorization_from(response)
|
|
213
|
-
response[:txn_id]
|
|
230
|
+
[response[:txn_id], response[:purchase_order_no], response[:preauth_id], response[:amount]].join('*')
|
|
214
231
|
end
|
|
215
232
|
|
|
216
233
|
def message_from(response)
|
|
@@ -177,6 +177,7 @@ module ActiveMerchant #:nodoc:
|
|
|
177
177
|
|
|
178
178
|
def post_data(action, parameters = {})
|
|
179
179
|
parameters[:account_id] = @options[:login]
|
|
180
|
+
parameters[:site_tag] = @options[:site_tag] if @options[:site_tag].present?
|
|
180
181
|
parameters[:pay_type] = 'C'
|
|
181
182
|
parameters[:tran_type] = TRANSACTIONS[action]
|
|
182
183
|
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
module ActiveMerchant #:nodoc:
|
|
2
|
+
module Billing #:nodoc:
|
|
3
|
+
#
|
|
4
|
+
# NETPAY Gateway
|
|
5
|
+
#
|
|
6
|
+
# Support for NETPAY's HTTP Connector payment gateway in Mexico.
|
|
7
|
+
#
|
|
8
|
+
# The gateway sends requests as HTTP POST and receives the response details
|
|
9
|
+
# in the HTTP header, making the process really rather simple.
|
|
10
|
+
#
|
|
11
|
+
# Support for calls to the authorize and capture methods have been included
|
|
12
|
+
# as per the Netpay manuals, however, your millage may vary with these
|
|
13
|
+
# methods. At the time of writing (January 2013) they were not fully
|
|
14
|
+
# supported by the production or test gateways. This situation is
|
|
15
|
+
# expected to change within a few weeks/months.
|
|
16
|
+
#
|
|
17
|
+
# Purchases can be cancelled (`#void`) only within 24 hours of the
|
|
18
|
+
# transaction. After this, a refund should be performed instead.
|
|
19
|
+
#
|
|
20
|
+
# In addition to the regular ActiveMerchant transaction options, NETPAY
|
|
21
|
+
# also supports a `:mode` parameter. This allows testing to be peformed
|
|
22
|
+
# in production and force specific results.
|
|
23
|
+
#
|
|
24
|
+
# * 'P' - Production
|
|
25
|
+
# * 'A' - Approved
|
|
26
|
+
# * 'D' - Declined
|
|
27
|
+
# * 'R' - Random (Approved or Declined)
|
|
28
|
+
# * 'T' - Test
|
|
29
|
+
#
|
|
30
|
+
# For example:
|
|
31
|
+
#
|
|
32
|
+
# response = @gateway.purchase(1000, card, :mode => 'D')
|
|
33
|
+
# response.success # false
|
|
34
|
+
#
|
|
35
|
+
class NetpayGateway < Gateway
|
|
36
|
+
self.test_url = 'http://200.57.87.243:8855'
|
|
37
|
+
self.live_url = 'https://suite.netpay.com.mx/acquirerprd'
|
|
38
|
+
|
|
39
|
+
# The countries the gateway supports merchants from as 2 digit ISO country codes
|
|
40
|
+
self.supported_countries = ['MX']
|
|
41
|
+
|
|
42
|
+
self.default_currency = 'MXN'
|
|
43
|
+
|
|
44
|
+
# The card types supported by the payment gateway
|
|
45
|
+
self.supported_cardtypes = [:visa, :master, :american_express, :diners_club]
|
|
46
|
+
|
|
47
|
+
# The homepage URL of the gateway
|
|
48
|
+
self.homepage_url = 'http://www.netpay.com.mx'
|
|
49
|
+
|
|
50
|
+
# The name of the gateway
|
|
51
|
+
self.display_name = 'NETPAY Gateway'
|
|
52
|
+
|
|
53
|
+
CURRENCY_CODES = {
|
|
54
|
+
"MXN" => '484'
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
# The header keys that we will provide in the response params hash
|
|
58
|
+
RESPONSE_KEYS = ['ResponseMsg', 'ResponseText', 'ResponseCode', 'TimeIn', 'TimeOut', 'AuthCode', 'OrderId', 'CardTypeName', 'MerchantId', 'IssuerAuthDate']
|
|
59
|
+
|
|
60
|
+
def initialize(options = {})
|
|
61
|
+
requires!(options, :store_id, :login, :password)
|
|
62
|
+
super
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Send an authorization request
|
|
66
|
+
def authorize(money, creditcard, options = {})
|
|
67
|
+
post = {}
|
|
68
|
+
add_invoice(post, options)
|
|
69
|
+
add_creditcard(post, creditcard)
|
|
70
|
+
add_customer_data(post, options)
|
|
71
|
+
add_amount(post, money, options)
|
|
72
|
+
|
|
73
|
+
commit('PreAuth', post, options)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Capture an authorization
|
|
77
|
+
def capture(money, authorization, options = {})
|
|
78
|
+
post = {}
|
|
79
|
+
add_order_id(post, order_id_from(authorization))
|
|
80
|
+
add_amount(post, money, options)
|
|
81
|
+
|
|
82
|
+
commit('PostAuth', post, options)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Cancel an auth/purchase within first 24 hours
|
|
86
|
+
def void(authorization, options = {})
|
|
87
|
+
post = {}
|
|
88
|
+
order_id, amount, currency = split_authorization(authorization)
|
|
89
|
+
add_order_id(post, order_id)
|
|
90
|
+
post['Total'] = (options[:amount] || amount)
|
|
91
|
+
post['CurrencyCode'] = currency
|
|
92
|
+
|
|
93
|
+
commit('Refund', post, options)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Make a purchase.
|
|
97
|
+
def purchase(money, creditcard, options = {})
|
|
98
|
+
post = {}
|
|
99
|
+
add_invoice(post, options)
|
|
100
|
+
add_creditcard(post, creditcard)
|
|
101
|
+
add_customer_data(post, options)
|
|
102
|
+
add_amount(post, money, options)
|
|
103
|
+
|
|
104
|
+
commit('Auth', post, options)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Perform a Credit transaction.
|
|
108
|
+
def refund(money, authorization, options = {})
|
|
109
|
+
post = {}
|
|
110
|
+
add_order_id(post, order_id_from(authorization))
|
|
111
|
+
add_amount(post, money, options)
|
|
112
|
+
|
|
113
|
+
#commit('Refund', post, options)
|
|
114
|
+
commit('Credit', post, options)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
private
|
|
118
|
+
|
|
119
|
+
def add_login_data(post)
|
|
120
|
+
post['StoreId'] = @options[:store_id]
|
|
121
|
+
post['UserName'] = @options[:login]
|
|
122
|
+
post['Password'] = @options[:password]
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def add_action(post, action, options)
|
|
126
|
+
post['ResourceName'] = action
|
|
127
|
+
post['ContentType'] = 'Transaction'
|
|
128
|
+
post['Mode'] = options[:mode] || 'P'
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def add_order_id(post, order_id)
|
|
132
|
+
post['OrderId'] = order_id
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def add_amount(post, money, options)
|
|
136
|
+
post['Total'] = amount(money)
|
|
137
|
+
post['CurrencyCode'] = currency_code(options[:currency] || currency(money))
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def add_customer_data(post, options)
|
|
141
|
+
post['IPAddress'] = options[:ip] unless options[:ip].blank?
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def add_invoice(post, options)
|
|
145
|
+
post['Comments'] = options[:description] if options[:description]
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def add_creditcard(post, creditcard)
|
|
149
|
+
post['CardNumber'] = creditcard.number
|
|
150
|
+
post['ExpDate'] = expdate(creditcard)
|
|
151
|
+
post['CustomerName'] = creditcard.name
|
|
152
|
+
post['CVV2'] = creditcard.verification_value unless creditcard.verification_value.nil?
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def build_authorization(request_params, response_params)
|
|
156
|
+
[response_params['OrderId'], request_params['Total'], request_params['CurrencyCode']].join('|')
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def split_authorization(authorization)
|
|
160
|
+
order_id, amount, currency = authorization.split("|")
|
|
161
|
+
[order_id, amount, currency]
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def order_id_from(authorization)
|
|
165
|
+
split_authorization(authorization).first
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def expdate(credit_card)
|
|
169
|
+
year = sprintf("%.4i", credit_card.year)
|
|
170
|
+
month = sprintf("%.2i", credit_card.month)
|
|
171
|
+
|
|
172
|
+
"#{month}/#{year[-2..-1]}"
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def url
|
|
176
|
+
test? ? test_url : live_url
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def parse(response, request_params)
|
|
180
|
+
response_params = params_from_response(response)
|
|
181
|
+
|
|
182
|
+
success = (response_params['ResponseCode'] == '00')
|
|
183
|
+
message = response_params['ResponseText'] || response_params['ResponseMsg']
|
|
184
|
+
options = @options.merge(:test => test?,
|
|
185
|
+
:authorization => build_authorization(request_params, response_params))
|
|
186
|
+
|
|
187
|
+
Response.new(success, message, response_params, options)
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def commit(action, parameters, options)
|
|
191
|
+
add_login_data(parameters)
|
|
192
|
+
add_action(parameters, action, options)
|
|
193
|
+
|
|
194
|
+
post = parameters.collect{|key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&")
|
|
195
|
+
parse(ssl_post(url, post), parameters)
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
# Override the regular handle response so we can access the headers
|
|
199
|
+
def handle_response(response)
|
|
200
|
+
case response.code.to_i
|
|
201
|
+
when 200...300
|
|
202
|
+
response
|
|
203
|
+
else
|
|
204
|
+
raise ResponseError.new(response)
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
# Return a hash containing all the useful, or informative values from netpay
|
|
209
|
+
def params_from_response(response)
|
|
210
|
+
params = {}
|
|
211
|
+
RESPONSE_KEYS.each do |k|
|
|
212
|
+
params[k] = response[k] unless response[k].to_s.empty?
|
|
213
|
+
end
|
|
214
|
+
params
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
def currency_code(currency)
|
|
218
|
+
return currency if currency =~ /^\d+$/
|
|
219
|
+
CURRENCY_CODES[currency]
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
end
|
|
@@ -154,23 +154,25 @@ module ActiveMerchant #:nodoc:
|
|
|
154
154
|
|
|
155
155
|
# Verify and transfer the specified amount.
|
|
156
156
|
def purchase(money, payment_source, options = {})
|
|
157
|
-
post
|
|
157
|
+
post = {}
|
|
158
|
+
action = options[:action] || 'SAL'
|
|
158
159
|
add_invoice(post, options)
|
|
159
160
|
add_payment_source(post, payment_source, options)
|
|
160
161
|
add_address(post, payment_source, options)
|
|
161
162
|
add_customer_data(post, options)
|
|
162
163
|
add_money(post, money, options)
|
|
163
|
-
commit(
|
|
164
|
+
commit(action, post)
|
|
164
165
|
end
|
|
165
166
|
|
|
166
167
|
# Complete a previously authorized transaction.
|
|
167
168
|
def capture(money, authorization, options = {})
|
|
168
|
-
post
|
|
169
|
+
post = {}
|
|
170
|
+
action = options[:action] || 'SAL'
|
|
169
171
|
add_authorization(post, reference_from(authorization))
|
|
170
172
|
add_invoice(post, options)
|
|
171
173
|
add_customer_data(post, options)
|
|
172
174
|
add_money(post, money, options)
|
|
173
|
-
commit(
|
|
175
|
+
commit(action, post)
|
|
174
176
|
end
|
|
175
177
|
|
|
176
178
|
# Cancels a previously authorized transaction.
|
|
@@ -90,7 +90,9 @@ module ActiveMerchant #:nodoc:
|
|
|
90
90
|
|
|
91
91
|
Response.new(successful?(response), message_from(response), hash_from_xml(response),
|
|
92
92
|
:test => test?,
|
|
93
|
-
:authorization => authorization_from(response)
|
|
93
|
+
:authorization => authorization_from(response),
|
|
94
|
+
:avs_result => { :code => avs_result_from(response) },
|
|
95
|
+
:cvv_result => cvv_result_from(response)
|
|
94
96
|
)
|
|
95
97
|
end
|
|
96
98
|
|
|
@@ -108,7 +110,15 @@ module ActiveMerchant #:nodoc:
|
|
|
108
110
|
end
|
|
109
111
|
|
|
110
112
|
def authorization_from(response)
|
|
111
|
-
|
|
113
|
+
get_text_from_document(response, '//confirmationNumber')
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def avs_result_from(response)
|
|
117
|
+
get_text_from_document(response, '//avsResponse')
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def cvv_result_from(response)
|
|
121
|
+
get_text_from_document(response, '//cvdResponse')
|
|
112
122
|
end
|
|
113
123
|
|
|
114
124
|
def hash_from_xml(response)
|
|
@@ -138,6 +148,11 @@ module ActiveMerchant #:nodoc:
|
|
|
138
148
|
xml.target!
|
|
139
149
|
end
|
|
140
150
|
|
|
151
|
+
def get_text_from_document(document, node)
|
|
152
|
+
node = REXML::XPath.first(document, node)
|
|
153
|
+
node && node.text
|
|
154
|
+
end
|
|
155
|
+
|
|
141
156
|
def cc_auth_request(money, opts)
|
|
142
157
|
xml_document('ccAuthRequestV1') do |xml|
|
|
143
158
|
build_merchant_account(xml, @options)
|
|
@@ -251,7 +266,7 @@ module ActiveMerchant #:nodoc:
|
|
|
251
266
|
xml.tag! 'country', CGI.escape(addr[:country] ) if addr[:country].present?
|
|
252
267
|
xml.tag! 'zip' , CGI.escape(addr[:zip] ) # this one's actually required
|
|
253
268
|
xml.tag! 'phone' , CGI.escape(addr[:phone] ) if addr[:phone].present?
|
|
254
|
-
|
|
269
|
+
xml.tag! 'email', CGI.escape(opts[:email]) if opts[:email]
|
|
255
270
|
end
|
|
256
271
|
end
|
|
257
272
|
|
|
@@ -125,9 +125,13 @@ module ActiveMerchant #:nodoc:
|
|
|
125
125
|
refund(money, authorization, options)
|
|
126
126
|
end
|
|
127
127
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
128
|
+
def void(authorization, options = {}, deprecated = {})
|
|
129
|
+
if(!options.kind_of?(Hash))
|
|
130
|
+
deprecated("Calling the void method with an amount parameter is deprecated and will be removed in a future version.")
|
|
131
|
+
return void(options, deprecated.merge(:amount => authorization))
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
order = build_void_request_xml(authorization, options)
|
|
131
135
|
commit(order, :void)
|
|
132
136
|
end
|
|
133
137
|
|
|
@@ -396,7 +400,7 @@ module ActiveMerchant #:nodoc:
|
|
|
396
400
|
xml.target!
|
|
397
401
|
end
|
|
398
402
|
|
|
399
|
-
def build_void_request_xml(
|
|
403
|
+
def build_void_request_xml(authorization, parameters = {})
|
|
400
404
|
tx_ref_num, order_id = split_authorization(authorization)
|
|
401
405
|
xml = xml_envelope
|
|
402
406
|
xml.tag! :Request do
|
|
@@ -404,7 +408,7 @@ module ActiveMerchant #:nodoc:
|
|
|
404
408
|
add_xml_credentials(xml)
|
|
405
409
|
xml.tag! :TxRefNum, tx_ref_num
|
|
406
410
|
xml.tag! :TxRefIdx, parameters[:transaction_index]
|
|
407
|
-
xml.tag! :AdjustedAmt, amount
|
|
411
|
+
xml.tag! :AdjustedAmt, parameters[:amount] # setting adjusted amount to nil will void entire amount
|
|
408
412
|
xml.tag! :OrderID, format_order_id(order_id || parameters[:order_id])
|
|
409
413
|
add_bin_merchant_and_terminal(xml, parameters)
|
|
410
414
|
end
|
|
@@ -140,6 +140,7 @@ module ActiveMerchant #:nodoc:
|
|
|
140
140
|
add_amount(result, money, options)
|
|
141
141
|
add_invoice(result, options)
|
|
142
142
|
add_address_verification_data(result, options)
|
|
143
|
+
add_optional_elements(result, options)
|
|
143
144
|
result
|
|
144
145
|
end
|
|
145
146
|
|
|
@@ -149,6 +150,7 @@ module ActiveMerchant #:nodoc:
|
|
|
149
150
|
add_amount(result, money, options)
|
|
150
151
|
add_invoice(result, options)
|
|
151
152
|
add_reference(result, identification)
|
|
153
|
+
add_optional_elements(result, options)
|
|
152
154
|
result
|
|
153
155
|
end
|
|
154
156
|
|
|
@@ -157,6 +159,7 @@ module ActiveMerchant #:nodoc:
|
|
|
157
159
|
add_credit_card(result, credit_card)
|
|
158
160
|
add_amount(result, 100, options) #need to make an auth request for $1
|
|
159
161
|
add_token_request(result, options)
|
|
162
|
+
add_optional_elements(result, options)
|
|
160
163
|
result
|
|
161
164
|
end
|
|
162
165
|
|
|
@@ -209,7 +212,7 @@ module ActiveMerchant #:nodoc:
|
|
|
209
212
|
|
|
210
213
|
def add_invoice(xml, options)
|
|
211
214
|
xml.add_element("TxnId").text = options[:order_id].to_s.slice(0, 16) unless options[:order_id].blank?
|
|
212
|
-
xml.add_element("MerchantReference").text = options[:description] unless options[:description].blank?
|
|
215
|
+
xml.add_element("MerchantReference").text = options[:description].to_s.slice(0, 50) unless options[:description].blank?
|
|
213
216
|
end
|
|
214
217
|
|
|
215
218
|
def add_address_verification_data(xml, options)
|
|
@@ -223,6 +226,52 @@ module ActiveMerchant #:nodoc:
|
|
|
223
226
|
xml.add_element("AvsPostCode").text = address[:zip]
|
|
224
227
|
end
|
|
225
228
|
|
|
229
|
+
# The options hash may contain optional data which will be passed
|
|
230
|
+
# through the the specialized optional fields at PaymentExpress
|
|
231
|
+
# as follows:
|
|
232
|
+
#
|
|
233
|
+
# {
|
|
234
|
+
# :client_type => :web, # Possible values are: :web, :ivr, :moto, :unattended, :internet, or :recurring
|
|
235
|
+
# :txn_data1 => "String up to 255 characters",
|
|
236
|
+
# :txn_data2 => "String up to 255 characters",
|
|
237
|
+
# :txn_data3 => "String up to 255 characters"
|
|
238
|
+
# }
|
|
239
|
+
#
|
|
240
|
+
# +:client_type+, while not documented for PxPost, will be sent as
|
|
241
|
+
# the +ClientType+ XML element as described in the documentation for
|
|
242
|
+
# the PaymentExpress WebService: http://www.paymentexpress.com/Technical_Resources/Ecommerce_NonHosted/WebService#clientType
|
|
243
|
+
# (PaymentExpress have confirmed that this value works the same in PxPost).
|
|
244
|
+
# The value sent for +:client_type+ will be normalized and sent
|
|
245
|
+
# as one of the explicit values allowed by PxPost:
|
|
246
|
+
#
|
|
247
|
+
# :web => "Web"
|
|
248
|
+
# :ivr => "IVR"
|
|
249
|
+
# :moto => "MOTO"
|
|
250
|
+
# :unattended => "Unattended"
|
|
251
|
+
# :internet => "Internet"
|
|
252
|
+
# :recurring => "Recurring"
|
|
253
|
+
#
|
|
254
|
+
# If you set the +:client_type+ to any value not listed above,
|
|
255
|
+
# the ClientType element WILL NOT BE INCLUDED at all in the
|
|
256
|
+
# POST data.
|
|
257
|
+
#
|
|
258
|
+
# +:txn_data1+, +:txn_data2+, and +:txn_data3+ will be sent as
|
|
259
|
+
# +TxnData1+, +TxnData2+, and +TxnData3+, respectively, and are
|
|
260
|
+
# free form fields of the merchant's choosing, as documented here:
|
|
261
|
+
# http://www.paymentexpress.com/technical_resources/ecommerce_nonhosted/pxpost.html#txndata
|
|
262
|
+
#
|
|
263
|
+
# These optional elements are added to all transaction types:
|
|
264
|
+
# +purchase+, +authorize+, +capture+, +refund+, +store+
|
|
265
|
+
def add_optional_elements(xml, options)
|
|
266
|
+
if client_type = normalized_client_type(options[:client_type])
|
|
267
|
+
xml.add_element("ClientType").text = client_type
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
xml.add_element("TxnData1").text = options[:txn_data1].to_s.slice(0,255) unless options[:txn_data1].blank?
|
|
271
|
+
xml.add_element("TxnData2").text = options[:txn_data2].to_s.slice(0,255) unless options[:txn_data2].blank?
|
|
272
|
+
xml.add_element("TxnData3").text = options[:txn_data3].to_s.slice(0,255) unless options[:txn_data3].blank?
|
|
273
|
+
end
|
|
274
|
+
|
|
226
275
|
def new_transaction
|
|
227
276
|
REXML::Document.new.add_element("Txn")
|
|
228
277
|
end
|
|
@@ -266,6 +315,18 @@ module ActiveMerchant #:nodoc:
|
|
|
266
315
|
def format_date(month, year)
|
|
267
316
|
"#{format(month, :two_digits)}#{format(year, :two_digits)}"
|
|
268
317
|
end
|
|
318
|
+
|
|
319
|
+
def normalized_client_type(client_type_from_options)
|
|
320
|
+
case client_type_from_options.to_s.downcase
|
|
321
|
+
when 'web' then "Web"
|
|
322
|
+
when 'ivr' then "IVR"
|
|
323
|
+
when 'moto' then "MOTO"
|
|
324
|
+
when 'unattended' then "Unattended"
|
|
325
|
+
when 'internet' then "Internet"
|
|
326
|
+
when 'recurring' then "Recurring"
|
|
327
|
+
else nil
|
|
328
|
+
end
|
|
329
|
+
end
|
|
269
330
|
end
|
|
270
331
|
|
|
271
332
|
class PaymentExpressResponse < Response
|