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.
@@ -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