activemerchant 1.46.0 → 1.47.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.
- 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
|