activemerchant 1.46.0 → 1.47.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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 payment_method.respond_to?(:track_data) && payment_method.track_data.present?
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 => response[:AVSResultCode] },
228
- :cvv_result => response[:CSCResultCode]
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
- commit_capture(action, authorization, build_request(action, options))
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
- when 'authtx'
204
- money = options.delete(:money)
205
- creditcard = options.delete(:creditcard)
206
- build_authorization(protocol, money, creditcard, options)
207
- when 'settletx'
208
- money = options.delete(:money)
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, "The remote server refused the connection"
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, derived_error_message(connection_errors, e.class)
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.message
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])
@@ -1,3 +1,3 @@
1
1
  module ActiveMerchant
2
- VERSION = "1.46.0"
2
+ VERSION = "1.47.0"
3
3
  end
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.46.0
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-01-21 00:00:00.000000000 Z
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