activemerchant 1.46.0 → 1.47.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/CHANGELOG +17 -0
- data/README.md +1 -1
- data/lib/active_merchant/billing.rb +1 -0
- data/lib/active_merchant/billing/credit_card_methods.rb +40 -5
- data/lib/active_merchant/billing/gateways.rb +2 -0
- data/lib/active_merchant/billing/gateways/authorize_net.rb +37 -11
- data/lib/active_merchant/billing/gateways/checkout.rb +1 -3
- data/lib/active_merchant/billing/gateways/cyber_source.rb +62 -18
- data/lib/active_merchant/billing/gateways/firstdata_e4.rb +14 -2
- data/lib/active_merchant/billing/gateways/flo2cash.rb +215 -0
- data/lib/active_merchant/billing/gateways/flo2cash_simple.rb +20 -0
- data/lib/active_merchant/billing/gateways/litle.rb +5 -3
- data/lib/active_merchant/billing/gateways/migs.rb +8 -2
- data/lib/active_merchant/billing/gateways/pay_gate_xml.rb +16 -26
- data/lib/active_merchant/billing/gateways/payflow.rb +4 -0
- data/lib/active_merchant/billing/gateways/paymill.rb +2 -2
- data/lib/active_merchant/billing/gateways/pin.rb +3 -2
- data/lib/active_merchant/billing/gateways/quickpay.rb +10 -5
- data/lib/active_merchant/billing/network_tokenization_credit_card.rb +16 -0
- data/lib/active_merchant/errors.rb +6 -0
- data/lib/active_merchant/network_connection_retries.rb +3 -3
- data/lib/active_merchant/version.rb +1 -1
- metadata +5 -17
- metadata.gz.sig +0 -0
- data/lib/active_merchant/billing/gateways/vindicia.rb +0 -385
@@ -0,0 +1,20 @@
|
|
1
|
+
module ActiveMerchant #:nodoc:
|
2
|
+
module Billing #:nodoc:
|
3
|
+
class Flo2cashSimpleGateway < Flo2cashGateway
|
4
|
+
self.display_name = 'Flo2Cash Simple'
|
5
|
+
|
6
|
+
def purchase(amount, payment_method, options={})
|
7
|
+
post = {}
|
8
|
+
add_invoice(post, amount, options)
|
9
|
+
add_payment_method(post, payment_method)
|
10
|
+
add_customer_data(post, options)
|
11
|
+
|
12
|
+
commit("ProcessPurchase", post)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Flo2Cash's "simple mode" does not support auth/capture
|
16
|
+
undef_method :authorize
|
17
|
+
undef_method :capture
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -157,7 +157,7 @@ module ActiveMerchant #:nodoc:
|
|
157
157
|
def add_auth_purchase_params(doc, money, payment_method, options)
|
158
158
|
doc.orderId(truncated(options[:order_id]))
|
159
159
|
doc.amount(money)
|
160
|
-
add_order_source(doc, payment_method)
|
160
|
+
add_order_source(doc, payment_method, options)
|
161
161
|
add_billing_address(doc, payment_method, options)
|
162
162
|
add_shipping_address(doc, payment_method, options)
|
163
163
|
add_payment_method(doc, payment_method)
|
@@ -225,8 +225,10 @@ module ActiveMerchant #:nodoc:
|
|
225
225
|
doc.phone(address[:phone]) unless address[:phone].blank?
|
226
226
|
end
|
227
227
|
|
228
|
-
def add_order_source(doc, payment_method)
|
229
|
-
if
|
228
|
+
def add_order_source(doc, payment_method, options)
|
229
|
+
if options[:order_source]
|
230
|
+
doc.orderSource(options[:order_source])
|
231
|
+
elsif payment_method.respond_to?(:track_data) && payment_method.track_data.present?
|
230
232
|
doc.orderSource('retail')
|
231
233
|
else
|
232
234
|
doc.orderSource('ecommerce')
|
@@ -220,12 +220,18 @@ module ActiveMerchant #:nodoc:
|
|
220
220
|
end
|
221
221
|
|
222
222
|
def response_object(response)
|
223
|
+
avs_response_code = response[:AVSResultCode]
|
224
|
+
avs_response_code = 'S' if avs_response_code == "Unsupported"
|
225
|
+
|
226
|
+
cvv_result_code = response[:CSCResultCode]
|
227
|
+
cvv_result_code = 'P' if cvv_result_code == "Unsupported"
|
228
|
+
|
223
229
|
Response.new(success?(response), response[:Message], response,
|
224
230
|
:test => test?,
|
225
231
|
:authorization => response[:TransactionNo],
|
226
232
|
:fraud_review => fraud_review?(response),
|
227
|
-
:avs_result => { :code =>
|
228
|
-
:cvv_result =>
|
233
|
+
:avs_result => { :code => avs_response_code },
|
234
|
+
:cvv_result => cvv_result_code
|
229
235
|
)
|
230
236
|
end
|
231
237
|
|
@@ -178,7 +178,7 @@ module ActiveMerchant #:nodoc:
|
|
178
178
|
action = 'settletx'
|
179
179
|
|
180
180
|
options.merge!(:money => money, :authorization => authorization)
|
181
|
-
|
181
|
+
commit(action, build_request(action, options), authorization)
|
182
182
|
end
|
183
183
|
|
184
184
|
def refund(money, authorization, options={})
|
@@ -199,19 +199,16 @@ module ActiveMerchant #:nodoc:
|
|
199
199
|
xml.instruct!
|
200
200
|
|
201
201
|
xml.tag! 'protocol', :ver => API_VERSION, :pgid => (test? ? TEST_ID : @options[:login]), :pwd => @options[:password] do |protocol|
|
202
|
+
money = options.delete(:money)
|
203
|
+
authorization = options.delete(:authorization)
|
204
|
+
creditcard = options.delete(:creditcard)
|
202
205
|
case action
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
authorization = options.delete(:authorization)
|
210
|
-
build_capture(protocol, money, authorization, options)
|
211
|
-
when 'refundtx'
|
212
|
-
money = options.delete(:money)
|
213
|
-
authorization = options.delete(:authorization)
|
214
|
-
build_refund(protocol, money, authorization, options)
|
206
|
+
when 'authtx'
|
207
|
+
build_authorization(protocol, money, creditcard, options)
|
208
|
+
when 'settletx'
|
209
|
+
build_capture(protocol, money, authorization, options)
|
210
|
+
when 'refundtx'
|
211
|
+
build_refund(protocol, money, authorization, options)
|
215
212
|
else
|
216
213
|
raise "no action specified for build_request"
|
217
214
|
end
|
@@ -229,7 +226,9 @@ module ActiveMerchant #:nodoc:
|
|
229
226
|
:budp => 0,
|
230
227
|
:amt => amount(money),
|
231
228
|
:cur => (options[:currency] || currency(money)),
|
232
|
-
:cvv => creditcard.verification_value
|
229
|
+
:cvv => creditcard.verification_value,
|
230
|
+
:email => options[:email],
|
231
|
+
:ip => options[:ip]
|
233
232
|
}
|
234
233
|
end
|
235
234
|
|
@@ -262,19 +261,11 @@ module ActiveMerchant #:nodoc:
|
|
262
261
|
hash
|
263
262
|
end
|
264
263
|
|
265
|
-
def commit(action, request)
|
264
|
+
def commit(action, request, authorization = nil)
|
266
265
|
response = parse(action, ssl_post(self.live_url, request))
|
267
266
|
Response.new(successful?(response), message_from(response), response,
|
268
267
|
:test => test?,
|
269
|
-
:authorization => response[:tid]
|
270
|
-
)
|
271
|
-
end
|
272
|
-
|
273
|
-
def commit_capture(action, authorization, request)
|
274
|
-
response = parse(action, ssl_post(self.live_url, request))
|
275
|
-
Response.new(successful?(response), message_from(response), response,
|
276
|
-
:test => test?,
|
277
|
-
:authorization => authorization
|
268
|
+
:authorization => authorization ? authorization : response[:tid]
|
278
269
|
)
|
279
270
|
end
|
280
271
|
|
@@ -283,5 +274,4 @@ module ActiveMerchant #:nodoc:
|
|
283
274
|
end
|
284
275
|
end
|
285
276
|
end
|
286
|
-
end
|
287
|
-
|
277
|
+
end
|
@@ -44,6 +44,10 @@ module ActiveMerchant #:nodoc:
|
|
44
44
|
commit(build_reference_request(:credit, money, reference, options), options)
|
45
45
|
end
|
46
46
|
|
47
|
+
def verify(payment, options={})
|
48
|
+
authorize(0, payment, options)
|
49
|
+
end
|
50
|
+
|
47
51
|
# Adds or modifies a recurring Payflow profile. See the Payflow Pro Recurring Billing Guide for more details:
|
48
52
|
# https://www.paypal.com/en_US/pdf/PayflowPro_RecurringBilling_Guide.pdf
|
49
53
|
#
|
@@ -85,7 +85,7 @@ module ActiveMerchant #:nodoc:
|
|
85
85
|
:test => (parsed['mode'] == 'test'),
|
86
86
|
}
|
87
87
|
|
88
|
-
succeeded = (parsed['data'] == []) || (parsed['data']['response_code'] == 20000)
|
88
|
+
succeeded = (parsed['data'] == []) || (parsed['data']['response_code'].to_i == 20000)
|
89
89
|
Response.new(succeeded, response_message(parsed), parsed, options)
|
90
90
|
end
|
91
91
|
|
@@ -230,7 +230,7 @@ module ActiveMerchant #:nodoc:
|
|
230
230
|
return parsed_response["error"] if parsed_response["error"]
|
231
231
|
return "Transaction approved." if (parsed_response['data'] == [])
|
232
232
|
|
233
|
-
code = parsed_response["data"]["response_code"]
|
233
|
+
code = parsed_response["data"]["response_code"].to_i
|
234
234
|
RESPONSE_CODES[code] || code.to_s
|
235
235
|
end
|
236
236
|
|
@@ -152,8 +152,6 @@ module ActiveMerchant #:nodoc:
|
|
152
152
|
body = parse(raw_response)
|
153
153
|
rescue ResponseError => e
|
154
154
|
body = parse(e.response.body)
|
155
|
-
rescue JSON::ParserError
|
156
|
-
return unparsable_response(raw_response)
|
157
155
|
end
|
158
156
|
|
159
157
|
if body["response"]
|
@@ -161,6 +159,9 @@ module ActiveMerchant #:nodoc:
|
|
161
159
|
elsif body["error"]
|
162
160
|
error_response(body)
|
163
161
|
end
|
162
|
+
|
163
|
+
rescue JSON::ParserError
|
164
|
+
return unparsable_response(raw_response)
|
164
165
|
end
|
165
166
|
|
166
167
|
def success_response(body)
|
@@ -19,7 +19,7 @@ module ActiveMerchant #:nodoc:
|
|
19
19
|
currency autocapture cardnumber expirationdate
|
20
20
|
cvd cardtypelock testmode),
|
21
21
|
|
22
|
-
:capture => %w(protocol msgtype merchant amount transaction),
|
22
|
+
:capture => %w(protocol msgtype merchant amount finalize transaction),
|
23
23
|
|
24
24
|
:cancel => %w(protocol msgtype merchant transaction),
|
25
25
|
|
@@ -44,7 +44,7 @@ module ActiveMerchant #:nodoc:
|
|
44
44
|
fraud_http_accept_encoding fraud_http_accept_charset
|
45
45
|
fraud_http_referer fraud_http_user_agent apikey),
|
46
46
|
|
47
|
-
:capture => %w(protocol msgtype merchant amount transaction apikey),
|
47
|
+
:capture => %w(protocol msgtype merchant amount finalize transaction apikey),
|
48
48
|
|
49
49
|
:cancel => %w(protocol msgtype merchant transaction apikey),
|
50
50
|
|
@@ -72,7 +72,7 @@ module ActiveMerchant #:nodoc:
|
|
72
72
|
fraud_http_accept_encoding fraud_http_accept_charset
|
73
73
|
fraud_http_referer fraud_http_user_agent apikey),
|
74
74
|
|
75
|
-
:capture => %w(protocol msgtype merchant amount transaction apikey),
|
75
|
+
:capture => %w(protocol msgtype merchant amount finalize transaction apikey),
|
76
76
|
|
77
77
|
:cancel => %w(protocol msgtype merchant transaction apikey),
|
78
78
|
|
@@ -100,7 +100,7 @@ module ActiveMerchant #:nodoc:
|
|
100
100
|
fraud_http_accept_encoding fraud_http_accept_charset
|
101
101
|
fraud_http_referer fraud_http_user_agent apikey),
|
102
102
|
|
103
|
-
:capture => %w(protocol msgtype merchant amount transaction
|
103
|
+
:capture => %w(protocol msgtype merchant amount finalize transaction
|
104
104
|
apikey),
|
105
105
|
|
106
106
|
:cancel => %w(protocol msgtype merchant transaction apikey),
|
@@ -129,7 +129,7 @@ module ActiveMerchant #:nodoc:
|
|
129
129
|
fraud_http_accept_encoding fraud_http_accept_charset
|
130
130
|
fraud_http_referer fraud_http_user_agent apikey),
|
131
131
|
|
132
|
-
:capture => %w(protocol msgtype merchant amount transaction
|
132
|
+
:capture => %w(protocol msgtype merchant amount finalize transaction
|
133
133
|
apikey),
|
134
134
|
|
135
135
|
:cancel => %w(protocol msgtype merchant transaction apikey),
|
@@ -196,6 +196,7 @@ module ActiveMerchant #:nodoc:
|
|
196
196
|
def capture(money, authorization, options = {})
|
197
197
|
post = {}
|
198
198
|
|
199
|
+
add_finalize(post, options)
|
199
200
|
add_reference(post, authorization)
|
200
201
|
add_amount_without_currency(post, money)
|
201
202
|
commit(:capture, post)
|
@@ -300,6 +301,10 @@ module ActiveMerchant #:nodoc:
|
|
300
301
|
end
|
301
302
|
end
|
302
303
|
|
304
|
+
def add_finalize(post, options)
|
305
|
+
post[:finalize] = options[:finalize] ? '1' : '0'
|
306
|
+
end
|
307
|
+
|
303
308
|
def commit(action, params)
|
304
309
|
response = parse(ssl_post(self.live_url, post_data(action, params)))
|
305
310
|
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module ActiveMerchant #:nodoc:
|
2
|
+
module Billing #:nodoc:
|
3
|
+
class NetworkTokenizationCreditCard < CreditCard
|
4
|
+
# A +NetworkTokenizationCreditCard+ object represents a tokenized credit card
|
5
|
+
# using the EMV Network Tokenization specification, http://www.emvco.com/specifications.aspx?id=263.
|
6
|
+
#
|
7
|
+
# It includes all fields of the +CreditCard+ class with additional fields for
|
8
|
+
# verification data that must be given to gateways through existing fields (3DS / EMV).
|
9
|
+
#
|
10
|
+
# The only tested usage of this at the moment is with an Apple Pay decrypted PKPaymentToken,
|
11
|
+
# https://developer.apple.com/library/ios/documentation/PassKit/Reference/PaymentTokenJSON/PaymentTokenJSON.html
|
12
|
+
|
13
|
+
attr_accessor :payment_cryptogram, :eci, :transaction_id
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -3,6 +3,12 @@ module ActiveMerchant #:nodoc:
|
|
3
3
|
end
|
4
4
|
|
5
5
|
class ConnectionError < ActiveMerchantError # :nodoc:
|
6
|
+
attr_reader :triggering_exception
|
7
|
+
|
8
|
+
def initialize(message, triggering_exception)
|
9
|
+
super(message)
|
10
|
+
@triggering_exception = triggering_exception
|
11
|
+
end
|
6
12
|
end
|
7
13
|
|
8
14
|
class RetriableConnectionError < ConnectionError # :nodoc:
|
@@ -21,14 +21,14 @@ module ActiveMerchant
|
|
21
21
|
begin
|
22
22
|
yield
|
23
23
|
rescue Errno::ECONNREFUSED => e
|
24
|
-
raise ActiveMerchant::RetriableConnectionError
|
24
|
+
raise ActiveMerchant::RetriableConnectionError.new("The remote server refused the connection", e)
|
25
25
|
rescue OpenSSL::X509::CertificateError => e
|
26
26
|
NetworkConnectionRetries.log(options[:logger], :error, e.message, options[:tag])
|
27
27
|
raise ActiveMerchant::ClientCertificateError, "The remote server did not accept the provided SSL certificate"
|
28
28
|
rescue Zlib::BufError => e
|
29
29
|
raise ActiveMerchant::InvalidResponseError, "The remote server replied with an invalid response"
|
30
30
|
rescue *connection_errors.keys => e
|
31
|
-
raise ActiveMerchant::ConnectionError
|
31
|
+
raise ActiveMerchant::ConnectionError.new(derived_error_message(connection_errors, e.class), e)
|
32
32
|
end
|
33
33
|
end
|
34
34
|
end
|
@@ -50,7 +50,7 @@ module ActiveMerchant
|
|
50
50
|
|
51
51
|
log_with_retry_details(options[:logger], initial_retries-retries, Time.now.to_f - request_start, e.message, options[:tag])
|
52
52
|
retry unless retries.zero?
|
53
|
-
raise ActiveMerchant::ConnectionError, e
|
53
|
+
raise ActiveMerchant::ConnectionError.new(e.message, e)
|
54
54
|
rescue ActiveMerchant::ConnectionError, ActiveMerchant::InvalidResponseError => e
|
55
55
|
retries -= 1
|
56
56
|
log_with_retry_details(options[:logger], initial_retries-retries, Time.now.to_f - request_start, e.message, options[:tag])
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activemerchant
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.47.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tobias Luetke
|
@@ -30,7 +30,7 @@ cert_chain:
|
|
30
30
|
fl3hbtVFTqbOlwL9vy1fudXcolIE/ZTcxQ+er07ZFZdKCXayR9PPs64heamfn0fp
|
31
31
|
TConQSX2BnZdhIEYW+cKzEC/bLc=
|
32
32
|
-----END CERTIFICATE-----
|
33
|
-
date: 2015-
|
33
|
+
date: 2015-02-26 00:00:00.000000000 Z
|
34
34
|
dependencies:
|
35
35
|
- !ruby/object:Gem::Dependency
|
36
36
|
name: activesupport
|
@@ -142,20 +142,6 @@ dependencies:
|
|
142
142
|
- - "~>"
|
143
143
|
- !ruby/object:Gem::Version
|
144
144
|
version: '1'
|
145
|
-
- !ruby/object:Gem::Dependency
|
146
|
-
name: rails
|
147
|
-
requirement: !ruby/object:Gem::Requirement
|
148
|
-
requirements:
|
149
|
-
- - ">="
|
150
|
-
- !ruby/object:Gem::Version
|
151
|
-
version: 3.2.14
|
152
|
-
type: :development
|
153
|
-
prerelease: false
|
154
|
-
version_requirements: !ruby/object:Gem::Requirement
|
155
|
-
requirements:
|
156
|
-
- - ">="
|
157
|
-
- !ruby/object:Gem::Version
|
158
|
-
version: 3.2.14
|
159
145
|
- !ruby/object:Gem::Dependency
|
160
146
|
name: thor
|
161
147
|
requirement: !ruby/object:Gem::Requirement
|
@@ -244,6 +230,8 @@ files:
|
|
244
230
|
- lib/active_merchant/billing/gateways/first_giving.rb
|
245
231
|
- lib/active_merchant/billing/gateways/first_pay.rb
|
246
232
|
- lib/active_merchant/billing/gateways/firstdata_e4.rb
|
233
|
+
- lib/active_merchant/billing/gateways/flo2cash.rb
|
234
|
+
- lib/active_merchant/billing/gateways/flo2cash_simple.rb
|
247
235
|
- lib/active_merchant/billing/gateways/garanti.rb
|
248
236
|
- lib/active_merchant/billing/gateways/global_transport.rb
|
249
237
|
- lib/active_merchant/billing/gateways/hdfc.rb
|
@@ -352,13 +340,13 @@ files:
|
|
352
340
|
- lib/active_merchant/billing/gateways/usa_epay_transaction.rb
|
353
341
|
- lib/active_merchant/billing/gateways/verifi.rb
|
354
342
|
- lib/active_merchant/billing/gateways/viaklix.rb
|
355
|
-
- lib/active_merchant/billing/gateways/vindicia.rb
|
356
343
|
- lib/active_merchant/billing/gateways/webpay.rb
|
357
344
|
- lib/active_merchant/billing/gateways/wepay.rb
|
358
345
|
- lib/active_merchant/billing/gateways/wirecard.rb
|
359
346
|
- lib/active_merchant/billing/gateways/worldpay.rb
|
360
347
|
- lib/active_merchant/billing/gateways/worldpay_us.rb
|
361
348
|
- lib/active_merchant/billing/model.rb
|
349
|
+
- lib/active_merchant/billing/network_tokenization_credit_card.rb
|
362
350
|
- lib/active_merchant/billing/payment_token.rb
|
363
351
|
- lib/active_merchant/billing/rails.rb
|
364
352
|
- lib/active_merchant/billing/response.rb
|
metadata.gz.sig
CHANGED
Binary file
|
@@ -1,385 +0,0 @@
|
|
1
|
-
require 'i18n/core_ext/string/interpolate'
|
2
|
-
|
3
|
-
module ActiveMerchant #:nodoc:
|
4
|
-
module Billing #:nodoc:
|
5
|
-
|
6
|
-
# For more information on the Vindicia Gateway please visit their {website}[http://vindicia.com/]
|
7
|
-
#
|
8
|
-
# The login and password are not the username and password you use to
|
9
|
-
# login to the Vindicia Merchant Portal.
|
10
|
-
#
|
11
|
-
# ==== Recurring Billing
|
12
|
-
#
|
13
|
-
# AutoBills are an feature of Vindicia's API that allows for creating and managing subscriptions.
|
14
|
-
#
|
15
|
-
# For more information about Vindicia's API and various other services visit their {Resource Center}[http://www.vindicia.com/resources/index.html]
|
16
|
-
class VindiciaGateway < Gateway
|
17
|
-
self.supported_countries = %w{US CA GB AU MX BR DE KR CN HK}
|
18
|
-
self.supported_cardtypes = [:visa, :master, :american_express, :discover]
|
19
|
-
self.homepage_url = 'http://www.vindicia.com/'
|
20
|
-
self.display_name = 'Vindicia'
|
21
|
-
|
22
|
-
class_attribute :test_url, :live_url
|
23
|
-
|
24
|
-
self.test_url = "https://soap.prodtest.sj.vindicia.com/soap.pl"
|
25
|
-
self.live_url = "http://soap.vindicia.com/soap.pl"
|
26
|
-
|
27
|
-
# Creates a new VindiciaGateway
|
28
|
-
#
|
29
|
-
# The gateway requires that a valid login and password be passed
|
30
|
-
# in the +options+ hash.
|
31
|
-
#
|
32
|
-
# ==== Options
|
33
|
-
#
|
34
|
-
# * <tt>:login</tt> -- Vindicia SOAP login (REQUIRED)
|
35
|
-
# * <tt>:password</tt> -- Vindicia SOAP password (REQUIRED)
|
36
|
-
# * <tt>:api_version</tt> -- Vindicia API Version - defaults to 3.6 (OPTIONAL)
|
37
|
-
# * <tt>:account_id</tt> -- Account Id which all transactions will be run against. (REQUIRED)
|
38
|
-
# * <tt>:transaction_prefix</tt> -- Prefix to order id for one-time transactions - defaults to 'X' (OPTIONAL
|
39
|
-
# * <tt>:min_chargeback_probability</tt> -- Minimum score for chargebacks - defaults to 65 (OPTIONAL)
|
40
|
-
# * <tt>:cvn_success</tt> -- Array of valid CVN Check return values - defaults to [M, P] (OPTIONAL)
|
41
|
-
# * <tt>:avs_success</tt> -- Array of valid AVS Check return values - defaults to [X, Y, A, W, Z] (OPTIONAL)
|
42
|
-
def initialize(options = {})
|
43
|
-
requires!(options, :login, :password, :account_id)
|
44
|
-
super
|
45
|
-
|
46
|
-
@account_id = options[:account_id]
|
47
|
-
|
48
|
-
@transaction_prefix = options[:transaction_prefix] || "X"
|
49
|
-
|
50
|
-
@min_chargeback_probability = options[:min_chargeback_probability] || 65
|
51
|
-
@cvn_success = options[:cvn_success] || %w{M P}
|
52
|
-
@avs_success = options[:avs_success] || %w{X Y A W Z}
|
53
|
-
|
54
|
-
@allowed_authorization_statuses = %w{Authorized}
|
55
|
-
end
|
56
|
-
|
57
|
-
# Perform a purchase, which is essentially an authorization and capture in a single operation.
|
58
|
-
#
|
59
|
-
# ==== Parameters
|
60
|
-
#
|
61
|
-
# * <tt>money</tt> -- The amount to be purchased as an Integer value in cents.
|
62
|
-
# * <tt>creditcard</tt> -- The CreditCard details for the transaction.
|
63
|
-
# * <tt>options</tt> -- A hash of optional parameters.
|
64
|
-
def purchase(money, creditcard, options = {})
|
65
|
-
response = authorize(money, creditcard, options)
|
66
|
-
return response if !response.success? || response.fraud_review?
|
67
|
-
|
68
|
-
capture(money, response.authorization, options)
|
69
|
-
end
|
70
|
-
|
71
|
-
# Performs an authorization, which reserves the funds on the customer's credit card, but does not
|
72
|
-
# charge the card.
|
73
|
-
#
|
74
|
-
# ==== Parameters
|
75
|
-
#
|
76
|
-
# * <tt>money</tt> -- The amount to be authorized as an Integer value in cents.
|
77
|
-
# * <tt>creditcard</tt> -- The CreditCard details for the transaction.
|
78
|
-
# * <tt>options</tt> -- A hash of optional parameters.
|
79
|
-
def authorize(money, creditcard, options = {})
|
80
|
-
vindicia_transaction = authorize_transaction(money, creditcard, options)
|
81
|
-
response = check_transaction(vindicia_transaction)
|
82
|
-
|
83
|
-
# if this response is under fraud review because of our AVS/CVV checks void the transaction
|
84
|
-
if !response.success? && response.fraud_review? && !response.authorization.blank?
|
85
|
-
void_response = void([vindicia_transaction[:transaction][:merchantTransactionId]], options)
|
86
|
-
if void_response.success?
|
87
|
-
return response
|
88
|
-
else
|
89
|
-
return void_response
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
response
|
94
|
-
end
|
95
|
-
|
96
|
-
# Captures the funds from an authorized transaction.
|
97
|
-
#
|
98
|
-
# ==== Parameters
|
99
|
-
#
|
100
|
-
# * <tt>money</tt> -- The amount to be captured as an Integer value in cents.
|
101
|
-
# * <tt>identification</tt> -- The authorization returned from the previous authorize request.
|
102
|
-
def capture(money, identification, options = {})
|
103
|
-
response = post(:capture) do |xml|
|
104
|
-
add_hash(xml, transactions: [{ merchantTransactionId: identification }])
|
105
|
-
end
|
106
|
-
|
107
|
-
if response[:return][:returnCode] != '200' || response[:qtyFail].to_i > 0
|
108
|
-
return fail(response)
|
109
|
-
end
|
110
|
-
|
111
|
-
success(response, identification)
|
112
|
-
end
|
113
|
-
|
114
|
-
# Void a previous transaction
|
115
|
-
#
|
116
|
-
# ==== Parameters
|
117
|
-
#
|
118
|
-
# * <tt>identification</tt> - The authorization returned from the previous authorize request.
|
119
|
-
# * <tt>options</tt> - Extra options (currently only :ip used)
|
120
|
-
def void(identification, options = {})
|
121
|
-
response = post(:cancel) do |xml|
|
122
|
-
add_hash(xml, transactions: [{
|
123
|
-
account: {merchantAccountId: @account_id},
|
124
|
-
merchantTransactionId: identification,
|
125
|
-
sourceIp: options[:ip]
|
126
|
-
}])
|
127
|
-
end
|
128
|
-
|
129
|
-
if response[:return][:returnCode] == '200' && response[:qtyFail].to_i == 0
|
130
|
-
success(response, identification)
|
131
|
-
else
|
132
|
-
fail(response)
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
# Perform a recurring billing, which is essentially a purchase and autobill setup in a single operation.
|
137
|
-
#
|
138
|
-
# ==== Parameters
|
139
|
-
#
|
140
|
-
# * <tt>money</tt> -- The amount to be purchased as an Integer value in cents.
|
141
|
-
# * <tt>creditcard</tt> -- The CreditCard details for the transaction.
|
142
|
-
# * <tt>options</tt> -- A hash of parameters.
|
143
|
-
#
|
144
|
-
# ==== Options
|
145
|
-
#
|
146
|
-
# * <tt>:product_sku</tt> -- The subscription product's sku
|
147
|
-
# * <tt>:autobill_prefix</tt> -- Prefix to order id for subscriptions - defaults to 'A' (OPTIONAL)
|
148
|
-
def recurring(money, creditcard, options={})
|
149
|
-
ActiveMerchant.deprecated RECURRING_DEPRECATION_MESSAGE
|
150
|
-
|
151
|
-
options[:recurring] = true
|
152
|
-
@autobill_prefix = options[:autobill_prefix] || "A"
|
153
|
-
|
154
|
-
response = authorize(money, creditcard, options)
|
155
|
-
return response if !response.success? || response.fraud_review?
|
156
|
-
|
157
|
-
capture_resp = capture(money, response.authorization, options)
|
158
|
-
return capture_resp if !response.success?
|
159
|
-
|
160
|
-
# Setting up a recurring AutoBill requires an associated product
|
161
|
-
requires!(options, :product_sku)
|
162
|
-
autobill_response = check_subscription(authorize_subscription(options.merge(:product_sku => options[:product_sku])))
|
163
|
-
|
164
|
-
if autobill_response.success?
|
165
|
-
autobill_response
|
166
|
-
else
|
167
|
-
# If the AutoBill fails to set-up, void the transaction and return it as the response
|
168
|
-
void_response = void(capture_resp.authorization, options)
|
169
|
-
if void_response.success?
|
170
|
-
return autobill_response
|
171
|
-
else
|
172
|
-
return void_response
|
173
|
-
end
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
|
-
private
|
178
|
-
|
179
|
-
def add_hash(xml, hash)
|
180
|
-
hash.each do |k,v|
|
181
|
-
add_element(xml, k, v)
|
182
|
-
end
|
183
|
-
end
|
184
|
-
|
185
|
-
def add_array(xml, elem, val)
|
186
|
-
val.each do |v|
|
187
|
-
add_element(xml, elem, v)
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
|
-
def add_element(xml, elem, val)
|
192
|
-
if val.is_a?(Hash)
|
193
|
-
xml.tag!(elem.to_s.camelize(:lower)) do |env|
|
194
|
-
add_hash(env, val)
|
195
|
-
end
|
196
|
-
elsif val.is_a?(Array)
|
197
|
-
add_array(xml, elem, val)
|
198
|
-
else
|
199
|
-
xml.tag!(elem.to_s.camelize(:lower), val.to_s)
|
200
|
-
end
|
201
|
-
end
|
202
|
-
|
203
|
-
def post(action, kind="Transaction")
|
204
|
-
xml = Builder::XmlMarkup.new
|
205
|
-
xml.instruct!(:xml, :encoding => "UTF-8")
|
206
|
-
xml.env :Envelope,
|
207
|
-
"xmlns:xsd" => "http://www.w3.org/2001/XMLSchema",
|
208
|
-
"xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance",
|
209
|
-
"xmlns:tns" => "http://soap.vindicia.com/v3_6/#{kind}",
|
210
|
-
"xmlns:env" => "http://schemas.xmlsoap.org/soap/envelope/" do
|
211
|
-
|
212
|
-
xml.env :Body do
|
213
|
-
xml.tns action.to_sym do
|
214
|
-
xml.auth do
|
215
|
-
xml.tag! :login, @options[:login]
|
216
|
-
xml.tag! :password, @options[:password]
|
217
|
-
xml.tag! :version, "3.6"
|
218
|
-
end
|
219
|
-
|
220
|
-
yield(xml)
|
221
|
-
end
|
222
|
-
end
|
223
|
-
end
|
224
|
-
|
225
|
-
url = (test? ? self.test_url : self.live_url)
|
226
|
-
parse(ssl_post(url, xml.target!, "Content-Type" => "text/xml"))
|
227
|
-
end
|
228
|
-
|
229
|
-
def parse(response)
|
230
|
-
# Vindicia always returns in the form of request_type_response => { actual_response }
|
231
|
-
Hash.from_xml(response)["Envelope"]["Body"].values.first.with_indifferent_access
|
232
|
-
end
|
233
|
-
|
234
|
-
def check_transaction(vindicia_transaction)
|
235
|
-
if vindicia_transaction[:return][:returnCode] == '200'
|
236
|
-
status_log = vindicia_transaction[:transaction][:statusLog].first
|
237
|
-
if status_log[:creditCardStatus]
|
238
|
-
avs = status_log[:creditCardStatus][:avsCode]
|
239
|
-
cvn = status_log[:creditCardStatus][:cvnCode]
|
240
|
-
end
|
241
|
-
|
242
|
-
if @allowed_authorization_statuses.include?(status_log[:status]) &&
|
243
|
-
check_cvn(cvn) && check_avs(avs)
|
244
|
-
|
245
|
-
success(vindicia_transaction,
|
246
|
-
vindicia_transaction[:transaction][:merchantTransactionId],
|
247
|
-
avs, cvn)
|
248
|
-
else
|
249
|
-
# If the transaction is authorized, but it didn't pass our AVS/CVV checks send the authorization along so
|
250
|
-
# that is gets voided. Otherwise, send no authorization.
|
251
|
-
fail(vindicia_transaction, avs, cvn, false,
|
252
|
-
@allowed_authorization_statuses.include?(status_log[:status]) ? vindicia_transaction[:transaction][:merchantTransactionId] : "")
|
253
|
-
end
|
254
|
-
else
|
255
|
-
# 406 = Chargeback risk score is higher than minChargebackProbability, transaction not authorized.
|
256
|
-
fail(vindicia_transaction, nil, nil, vindicia_transaction[:return][:return_code] == '406')
|
257
|
-
end
|
258
|
-
end
|
259
|
-
|
260
|
-
def authorize_transaction(money, creditcard, options)
|
261
|
-
parameters = {
|
262
|
-
:amount => amount(money),
|
263
|
-
:currency => options[:currency] || currency(money)
|
264
|
-
}
|
265
|
-
|
266
|
-
add_account_data(parameters, options)
|
267
|
-
add_customer_data(parameters, options)
|
268
|
-
add_payment_source(parameters, creditcard, options)
|
269
|
-
|
270
|
-
post(:auth) do |xml|
|
271
|
-
add_hash(xml, transaction: parameters, minChargebackProbability: @min_chargeback_probability)
|
272
|
-
end
|
273
|
-
end
|
274
|
-
|
275
|
-
def add_account_data(parameters, options)
|
276
|
-
parameters[:account] = { :merchantAccountId => @account_id }
|
277
|
-
parameters[:sourceIp] = options[:ip] if options[:ip]
|
278
|
-
end
|
279
|
-
|
280
|
-
def add_customer_data(parameters, options)
|
281
|
-
parameters[:merchantTransactionId] = transaction_id(options[:order_id])
|
282
|
-
parameters[:shippingAddress] = convert_am_address_to_vindicia(options[:shipping_address])
|
283
|
-
|
284
|
-
# Transaction items must be provided for tax purposes
|
285
|
-
requires!(options, :line_items)
|
286
|
-
parameters[:transactionItems] = options[:line_items]
|
287
|
-
|
288
|
-
if options[:recurring]
|
289
|
-
parameters[:nameValues] = [{:name => 'merchantAutoBillIdentifier', :value => autobill_id(options[:order_id])}]
|
290
|
-
end
|
291
|
-
end
|
292
|
-
|
293
|
-
def add_payment_source(parameters, creditcard, options)
|
294
|
-
parameters[:sourcePaymentMethod] = {
|
295
|
-
:type => 'CreditCard',
|
296
|
-
:creditCard => { :account => creditcard.number, :expirationDate => "%4d%02d" % [creditcard.year, creditcard.month] },
|
297
|
-
:accountHolderName => creditcard.name,
|
298
|
-
:nameValues => [{ :name => 'CVN', :value => creditcard.verification_value }],
|
299
|
-
:billingAddress => convert_am_address_to_vindicia(options[:billing_address] || options[:address]),
|
300
|
-
:customerSpecifiedType => creditcard.brand.capitalize,
|
301
|
-
:active => !!options[:recurring]
|
302
|
-
}
|
303
|
-
end
|
304
|
-
|
305
|
-
def authorize_subscription(options)
|
306
|
-
parameters = {}
|
307
|
-
|
308
|
-
add_account_data(parameters, options)
|
309
|
-
add_subscription_information(parameters, options)
|
310
|
-
|
311
|
-
post(:update, "AutoBill") do |xml|
|
312
|
-
add_hash(xml, autobill: parameters, validatePaymentMethod: false, minChargebackProbability: 100)
|
313
|
-
end
|
314
|
-
end
|
315
|
-
|
316
|
-
def check_subscription(vindicia_transaction)
|
317
|
-
if vindicia_transaction[:return][:returnCode] == '200'
|
318
|
-
if vindicia_transaction[:autobill] && vindicia_transaction[:autobill][:status] == "Active"
|
319
|
-
success(vindicia_transaction,
|
320
|
-
vindicia_transaction[:autobill][:merchantAutoBillId])
|
321
|
-
else
|
322
|
-
fail(vindicia_transaction)
|
323
|
-
end
|
324
|
-
else
|
325
|
-
fail(vindicia_transaction)
|
326
|
-
end
|
327
|
-
end
|
328
|
-
|
329
|
-
def add_subscription_information(parameters, options)
|
330
|
-
requires!(options, :product_sku)
|
331
|
-
|
332
|
-
if options[:shipping_address]
|
333
|
-
parameters[:account][:shipping_address] = options[:shipping_address]
|
334
|
-
end
|
335
|
-
|
336
|
-
parameters[:merchantAutoBillId] = autobill_id(options[:order_id])
|
337
|
-
parameters[:product] = { :merchantProductId => options[:product_sku] }
|
338
|
-
end
|
339
|
-
|
340
|
-
def check_avs(avs)
|
341
|
-
avs.blank? || @avs_success.include?(avs)
|
342
|
-
end
|
343
|
-
|
344
|
-
def check_cvn(cvn)
|
345
|
-
cvn.blank? || @cvn_success.include?(cvn)
|
346
|
-
end
|
347
|
-
|
348
|
-
def success(response, authorization, avs_code = nil, cvn_code = nil)
|
349
|
-
ActiveMerchant::Billing::Response.new(true, response[:return][:returnString], response,
|
350
|
-
{ :fraud_review => false, :authorization => authorization, :test => test?,
|
351
|
-
:avs_result => { :code => avs_code }, :cvv_result => cvn_code })
|
352
|
-
end
|
353
|
-
|
354
|
-
def fail(response, avs_code = nil, cvn_code = nil, fraud_review = false, authorization = "")
|
355
|
-
ActiveMerchant::Billing::Response.new(false, response[:return][:returnString], response,
|
356
|
-
{ :fraud_review => fraud_review || !authorization.blank?,
|
357
|
-
:authorization => authorization, :test => test?,
|
358
|
-
:avs_result => { :code => avs_code }, :cvv_result => cvn_code })
|
359
|
-
|
360
|
-
end
|
361
|
-
|
362
|
-
def autobill_id(order_id)
|
363
|
-
"#{@autobill_prefix}#{order_id}"
|
364
|
-
end
|
365
|
-
|
366
|
-
def transaction_id(order_id)
|
367
|
-
"#{@transaction_prefix}#{order_id}"
|
368
|
-
end
|
369
|
-
|
370
|
-
# Converts valid ActiveMerchant address hash to proper Vindicia format
|
371
|
-
def convert_am_address_to_vindicia(address)
|
372
|
-
return if address.nil?
|
373
|
-
|
374
|
-
convs = { :address1 => :addr1, :address2 => :addr2,
|
375
|
-
:state => :district, :zip => :postalCode }
|
376
|
-
|
377
|
-
vindicia_address = {}
|
378
|
-
address.each do |key, val|
|
379
|
-
vindicia_address[convs[key] || key] = val
|
380
|
-
end
|
381
|
-
vindicia_address
|
382
|
-
end
|
383
|
-
end
|
384
|
-
end
|
385
|
-
end
|