activemerchant 1.52.0 → 1.53.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +56 -0
  3. data/README.md +1 -1
  4. data/lib/active_merchant/billing/gateways/authorize_net.rb +4 -1
  5. data/lib/active_merchant/billing/gateways/banwire.rb +11 -0
  6. data/lib/active_merchant/billing/gateways/beanstream.rb +12 -1
  7. data/lib/active_merchant/billing/gateways/blue_pay.rb +519 -506
  8. data/lib/active_merchant/billing/gateways/borgun.rb +10 -0
  9. data/lib/active_merchant/billing/gateways/braintree/braintree_common.rb +13 -1
  10. data/lib/active_merchant/billing/gateways/braintree_blue.rb +2 -2
  11. data/lib/active_merchant/billing/gateways/braintree_orange.rb +0 -1
  12. data/lib/active_merchant/billing/gateways/card_stream.rb +14 -19
  13. data/lib/active_merchant/billing/gateways/cecabank.rb +11 -1
  14. data/lib/active_merchant/billing/gateways/cenpos.rb +62 -2
  15. data/lib/active_merchant/billing/gateways/checkout.rb +1 -1
  16. data/lib/active_merchant/billing/gateways/checkout_v2.rb +3 -3
  17. data/lib/active_merchant/billing/gateways/conekta.rb +11 -1
  18. data/lib/active_merchant/billing/gateways/creditcall.rb +208 -0
  19. data/lib/active_merchant/billing/gateways/epay.rb +12 -0
  20. data/lib/active_merchant/billing/gateways/eway.rb +11 -0
  21. data/lib/active_merchant/billing/gateways/eway_rapid.rb +11 -0
  22. data/lib/active_merchant/billing/gateways/forte.rb +238 -0
  23. data/lib/active_merchant/billing/gateways/iridium.rb +11 -0
  24. data/lib/active_merchant/billing/gateways/jetpay.rb +10 -1
  25. data/lib/active_merchant/billing/gateways/linkpoint.rb +11 -0
  26. data/lib/active_merchant/billing/gateways/litle.rb +8 -1
  27. data/lib/active_merchant/billing/gateways/merchant_ware_version_four.rb +1 -1
  28. data/lib/active_merchant/billing/gateways/micropayment.rb +167 -0
  29. data/lib/active_merchant/billing/gateways/migs.rb +13 -4
  30. data/lib/active_merchant/billing/gateways/monei.rb +1 -1
  31. data/lib/active_merchant/billing/gateways/netbilling.rb +11 -1
  32. data/lib/active_merchant/billing/gateways/nmi.rb +164 -178
  33. data/lib/active_merchant/billing/gateways/ogone.rb +50 -15
  34. data/lib/active_merchant/billing/gateways/openpay.rb +10 -1
  35. data/lib/active_merchant/billing/gateways/pac_net_raven.rb +5 -5
  36. data/lib/active_merchant/billing/gateways/payment_express.rb +11 -0
  37. data/lib/active_merchant/billing/gateways/paymill.rb +11 -0
  38. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +1 -1
  39. data/lib/active_merchant/billing/gateways/paystation.rb +3 -4
  40. data/lib/active_merchant/billing/gateways/pin.rb +10 -0
  41. data/lib/active_merchant/billing/gateways/quickpay/quickpay_v10.rb +106 -57
  42. data/lib/active_merchant/billing/gateways/realex.rb +10 -0
  43. data/lib/active_merchant/billing/gateways/redsys.rb +20 -0
  44. data/lib/active_merchant/billing/gateways/s5.rb +1 -0
  45. data/lib/active_merchant/billing/gateways/sage_pay.rb +11 -0
  46. data/lib/active_merchant/billing/gateways/secure_net.rb +1 -0
  47. data/lib/active_merchant/billing/gateways/stripe.rb +10 -4
  48. data/lib/active_merchant/billing/gateways/tns.rb +15 -4
  49. data/lib/active_merchant/billing/gateways/trust_commerce.rb +11 -0
  50. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +12 -2
  51. data/lib/active_merchant/billing/gateways/wirecard.rb +11 -1
  52. data/lib/active_merchant/billing/gateways/worldpay.rb +11 -0
  53. data/lib/active_merchant/billing/gateways/worldpay_online_payments.rb +1 -1
  54. data/lib/active_merchant/version.rb +1 -1
  55. metadata +5 -2
@@ -65,6 +65,16 @@ module ActiveMerchant #:nodoc:
65
65
  commit('void', post)
66
66
  end
67
67
 
68
+ def supports_scrubbing
69
+ true
70
+ end
71
+
72
+ def scrub(transcript)
73
+ transcript.gsub(%r((<PAN>)[^&]*(</PAN>))i, '\1[FILTERED]\2').
74
+ gsub(%r((<CVC2>)[^&]*(</CVC2>))i, '\1[FILTERED]\2').
75
+ gsub(%r(((?:\r\n)?Authorization: Basic )[^\r\n]+(\r\n)?), '\1[FILTERED]\2')
76
+ end
77
+
68
78
  private
69
79
 
70
80
  CURRENCY_CODES = Hash.new{|h,k| raise ArgumentError.new("Unsupported currency for HDFC: #{k}")}
@@ -1,9 +1,21 @@
1
1
  module BraintreeCommon
2
2
  def self.included(base)
3
- base.supported_countries = %w(US CA AU AD AT BE BG CY CZ DK EE FI FR GI DE GR HU IS IM IE IT LV LI LT LU MT MC NL NO PL PT RO SM SK SI ES SE CH TR GB)
3
+ base.supported_countries = %w(US CA AD AT BE BG HR CY CZ DK EE FI FR GI DE GR GG HU IS IM IE IT JE LV LI LT LU MT MC NL NO PL PT RO SM SK SI ES SE CH TR GB SG HK MY AU NZ)
4
4
  base.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :diners_club]
5
5
  base.homepage_url = 'http://www.braintreepaymentsolutions.com'
6
6
  base.display_name = 'Braintree'
7
7
  base.default_currency = 'USD'
8
8
  end
9
+
10
+ def supports_scrubbing
11
+ true
12
+ end
13
+
14
+ def scrub(transcript)
15
+ return "Not currently supported." if transcript.blank?
16
+ transcript.
17
+ gsub(%r((Authorization: Basic )\w+), '\1[FILTERED]').
18
+ gsub(%r((&?ccnumber=)\d*(&?)), '\1[FILTERED]\2').
19
+ gsub(%r((&?cvv=)\d*(&?)), '\1[FILTERED]\2')
20
+ end
9
21
  end
@@ -46,7 +46,7 @@ module ActiveMerchant #:nodoc:
46
46
 
47
47
  super
48
48
 
49
- if wiredump_device
49
+ if wiredump_device.present?
50
50
  logger = ((Logger === wiredump_device) ? wiredump_device : Logger.new(wiredump_device))
51
51
  logger.level = Logger::DEBUG
52
52
  else
@@ -60,7 +60,7 @@ module ActiveMerchant #:nodoc:
60
60
  :private_key => options[:private_key],
61
61
  :environment => (options[:environment] || (test? ? :sandbox : :production)).to_sym,
62
62
  :custom_user_agent => "ActiveMerchant #{ActiveMerchant::VERSION}",
63
- :logger => logger,
63
+ :logger => options[:logger] || logger,
64
64
  )
65
65
 
66
66
  @braintree_gateway = Braintree::Gateway.new( @configuration )
@@ -17,4 +17,3 @@ module ActiveMerchant #:nodoc:
17
17
  end
18
18
  end
19
19
  end
20
-
@@ -1,6 +1,9 @@
1
1
  module ActiveMerchant #:nodoc:
2
2
  module Billing #:nodoc:
3
3
  class CardStreamGateway < Gateway
4
+
5
+ THREEDSECURE_REQUIRED_DEPRECATION_MESSAGE = "Specifying the :threeDSRequired initialization option is deprecated. Please use the `:threeds_required => true` *transaction* option instead."
6
+
4
7
  self.test_url = self.live_url = 'https://gateway.cardstream.com/direct/'
5
8
  self.money_format = :cents
6
9
  self.default_currency = 'GBP'
@@ -61,10 +64,10 @@ module ActiveMerchant #:nodoc:
61
64
 
62
65
  def initialize(options = {})
63
66
  requires!(options, :login, :shared_secret)
67
+ @threeds_required = false
64
68
  if (options[:threeDSRequired])
65
- @threeDSRequired = options[:threeDSRequired]
66
- else
67
- @threeDSRequired = 'N'
69
+ ActiveMerchant.deprecated(THREEDSECURE_REQUIRED_DEPRECATION_MESSAGE)
70
+ @threeds_required = options[:threeDSRequired]
68
71
  end
69
72
  super
70
73
  end
@@ -74,7 +77,6 @@ module ActiveMerchant #:nodoc:
74
77
  add_amount(post, money, options)
75
78
  add_invoice(post, creditcard, money, options)
76
79
  add_creditcard(post, creditcard)
77
- add_address(post, creditcard, options)
78
80
  add_customer_data(post, options)
79
81
  commit('PREAUTH', post)
80
82
  end
@@ -84,7 +86,6 @@ module ActiveMerchant #:nodoc:
84
86
  add_amount(post, money, options)
85
87
  add_invoice(post, creditcard, money, options)
86
88
  add_creditcard(post, creditcard)
87
- add_address(post, creditcard, options)
88
89
  add_customer_data(post, options)
89
90
  commit('SALE', post)
90
91
  end
@@ -135,19 +136,12 @@ module ActiveMerchant #:nodoc:
135
136
  end
136
137
 
137
138
  def add_customer_data(post, options)
138
- address = options[:billing_address] || options[:address]
139
- add_pair(post, :customerPostCode, address[:zip])
140
139
  add_pair(post, :customerEmail, options[:email])
141
- add_pair(post, :customerPhone, options[:phone])
142
- end
143
-
144
- def add_address(post, creditcard, options)
145
- address = options[:billing_address] || options[:address]
146
-
147
- return if address.nil?
148
-
149
- add_pair(post, :customerAddress, address[:address1] + " " + (address[:address2].nil? ? "" : address[:address2]))
150
- add_pair(post, :customerPostCode, address[:zip])
140
+ if (address = options[:billing_address] || options[:address])
141
+ add_pair(post, :customerAddress, "#{address[:address1]} #{address[:address2]}".strip)
142
+ add_pair(post, :customerPostCode, address[:zip])
143
+ add_pair(post, :customerPhone, options[:phone])
144
+ end
151
145
  end
152
146
 
153
147
  def add_invoice(post, credit_card, money, options)
@@ -158,6 +152,9 @@ module ActiveMerchant #:nodoc:
158
152
  add_pair(post, :item1Description, (options[:description] || options[:order_id]).slice(0, 15))
159
153
  add_pair(post, :item1GrossValue, amount(money))
160
154
  end
155
+
156
+ add_pair(post, :threeDSRequired, (options[:threeds_required] || @threeds_required) ? 'Y' : 'N')
157
+ add_pair(post, :type, options[:type] || '1')
161
158
  end
162
159
 
163
160
  def add_creditcard(post, credit_card)
@@ -200,9 +197,7 @@ module ActiveMerchant #:nodoc:
200
197
  parameters.update(
201
198
  :merchantID => @options[:login],
202
199
  :action => action,
203
- :type => '1', #Ecommerce
204
200
  :countryCode => self.supported_countries[0],
205
- :threeDSRequired => @threeDSRequired #Disable 3d secure by default
206
201
  )
207
202
  # adds a signature to the post hash/array
208
203
  add_hmac(parameters)
@@ -94,6 +94,17 @@ module ActiveMerchant #:nodoc:
94
94
  commit(CECA_ACTION_REFUND, post)
95
95
  end
96
96
 
97
+ def supports_scrubbing
98
+ true
99
+ end
100
+
101
+ def scrub(transcript)
102
+ transcript.
103
+ gsub(%r((Authorization: Basic )\w+), '\1[FILTERED]').
104
+ gsub(%r((&?pan=)[^&]*)i, '\1[FILTERED]').
105
+ gsub(%r((&?cvv2=)[^&]*)i, '\1[FILTERED]')
106
+ end
107
+
97
108
  private
98
109
 
99
110
  def add_creditcard(post, creditcard)
@@ -226,4 +237,3 @@ module ActiveMerchant #:nodoc:
226
237
  end
227
238
  end
228
239
  end
229
-
@@ -148,7 +148,8 @@ module ActiveMerchant #:nodoc:
148
148
 
149
149
  data = build_request(post)
150
150
  begin
151
- raw = parse(ssl_post(self.live_url, data, headers))
151
+ xml = ssl_post(self.live_url, data, headers)
152
+ raw = parse(xml)
152
153
  rescue ActiveMerchant::ResponseError => e
153
154
  if(e.response.code == "500" && e.response.body.start_with?("<s:Envelope"))
154
155
  raw = {
@@ -166,7 +167,9 @@ module ActiveMerchant #:nodoc:
166
167
  raw,
167
168
  authorization: authorization_from(post, raw),
168
169
  error_code: error_code_from(succeeded, raw),
169
- test: test?
170
+ test: test?,
171
+ cvv_result: cvv_result_from_xml(xml),
172
+ avs_result: avs_result_from_xml(xml)
170
173
  )
171
174
  end
172
175
 
@@ -257,6 +260,63 @@ module ActiveMerchant #:nodoc:
257
260
  def error_code_from(succeeded, response)
258
261
  succeeded ? nil : STANDARD_ERROR_CODE_MAPPING[response[:result]]
259
262
  end
263
+
264
+ def cvv_result_from_xml(xml)
265
+ ActiveMerchant::Billing::CVVResult.new(cvv_result_code(xml))
266
+ end
267
+
268
+ def avs_result_from_xml(xml)
269
+ ActiveMerchant::Billing::AVSResult.new(code: avs_result_code(xml))
270
+ end
271
+
272
+ def cvv_result_code(xml)
273
+ cvv = validation_result_element(xml, "CVV")
274
+ return nil unless cvv
275
+ validation_result_matches?(*validation_result_element_text(cvv.parent)) ? 'M' : 'N'
276
+ end
277
+
278
+ def avs_result_code(xml)
279
+ billing_address_elem = validation_result_element(xml, "Billing Address")
280
+ zip_code_elem = validation_result_element(xml, "Zip Code")
281
+
282
+ return nil unless billing_address_elem && zip_code_elem
283
+
284
+ billing_matches = avs_result_matches(billing_address_elem)
285
+ zip_matches = avs_result_matches(zip_code_elem)
286
+
287
+ if billing_matches && zip_matches
288
+ 'D'
289
+ elsif !billing_matches && zip_matches
290
+ 'P'
291
+ elsif billing_matches && !zip_matches
292
+ 'B'
293
+ else
294
+ 'C'
295
+ end
296
+ end
297
+
298
+ def avs_result_matches(elem)
299
+ validation_result_matches?(*validation_result_element_text(elem.parent))
300
+ end
301
+
302
+ def validation_result_element(xml, name)
303
+ doc = Nokogiri::XML(xml)
304
+ doc.remove_namespaces!
305
+ doc.at_xpath("//ParameterValidationResultList//ParameterValidationResult//Name[text() = '#{name}']")
306
+ end
307
+
308
+ def validation_result_element_text(element)
309
+ result_text = element.elements.detect { |elem|
310
+ elem.name == "Result"
311
+ }.children.detect { |elem| elem.text }.text
312
+
313
+ result_text.split(";").collect(&:strip)
314
+ end
315
+
316
+ def validation_result_matches?(present, match)
317
+ present.downcase.start_with?('present') &&
318
+ match.downcase.start_with?('match')
319
+ end
260
320
  end
261
321
  end
262
322
  end
@@ -7,7 +7,7 @@ module ActiveMerchant #:nodoc:
7
7
  self.default_currency = 'USD'
8
8
  self.money_format = :decimals
9
9
 
10
- self.supported_countries = ['AT', 'BE', 'BG', 'CY', 'CZ', 'DE', 'DK', 'EE', 'ES', 'FI', 'FR', 'GR', 'HR', 'HU', 'IE', 'IS', 'IT', 'LI', 'LT', 'LU', 'LV', 'MT', 'MU', 'NL', 'NO', 'PL', 'PT', 'RO', 'SE', 'SI', 'SK', 'US']
10
+ self.supported_countries = ['AD', 'AT', 'BE', 'BG', 'CH', 'CY', 'CZ', 'DE', 'DK', 'EE', 'ES', 'FO', 'FI', 'FR', 'GB', 'GI', 'GL', 'GR', 'HR', 'HU', 'IE', 'IS', 'IL', 'IT', 'LI', 'LT', 'LU', 'LV', 'MC', 'MT', 'NL', 'NO', 'PL', 'PT', 'RO', 'SE', 'SI', 'SM', 'SK', 'SJ', 'TR', 'VA']
11
11
  self.supported_cardtypes = [:visa, :master, :american_express, :diners_club]
12
12
 
13
13
  self.homepage_url = 'https://www.checkout.com/'
@@ -3,10 +3,10 @@ module ActiveMerchant #:nodoc:
3
3
  class CheckoutV2Gateway < Gateway
4
4
  self.display_name = "Checkout.com V2 Gateway"
5
5
  self.homepage_url = "https://www.checkout.com/"
6
- self.test_url = "https://api2.checkout.com/v2"
7
- self.live_url = "http://sandbox.checkout.com/api2/v2"
6
+ self.live_url = "https://api2.checkout.com/v2"
7
+ self.test_url = "http://sandbox.checkout.com/api2/v2"
8
8
 
9
- self.supported_countries = ['AT', 'BE', 'BG', 'CY', 'CZ', 'DE', 'DK', 'EE', 'ES', 'FI', 'FR', 'GR', 'HR', 'HU', 'IE', 'IS', 'IT', 'LI', 'LT', 'LU', 'LV', 'MT', 'MU', 'NL', 'NO', 'PL', 'PT', 'RO', 'SE', 'SI', 'SK', 'US']
9
+ self.supported_countries = ['AD', 'AT', 'BE', 'BG', 'CH', 'CY', 'CZ', 'DE', 'DK', 'EE', 'ES', 'FO', 'FI', 'FR', 'GB', 'GI', 'GL', 'GR', 'HR', 'HU', 'IE', 'IS', 'IL', 'IT', 'LI', 'LT', 'LU', 'LV', 'MC', 'MT', 'NL', 'NO', 'PL', 'PT', 'RO', 'SE', 'SI', 'SM', 'SK', 'SJ', 'TR', 'VA']
10
10
  self.default_currency = "USD"
11
11
  self.money_format = :cents
12
12
  self.supported_cardtypes = [:visa, :master, :american_express, :diners_club]
@@ -55,6 +55,17 @@ module ActiveMerchant #:nodoc:
55
55
  commit(:post, "charges/#{identifier}/refund", post)
56
56
  end
57
57
 
58
+ def supports_scrubbing
59
+ true
60
+ end
61
+
62
+ def scrub(transcript)
63
+ transcript.
64
+ gsub(%r((Authorization: Basic )\w+), '\1[FILTERED]').
65
+ gsub(%r((&?card%5Bnumber%5D=)[^&]*)i, '\1[FILTERED]').
66
+ gsub(%r((&?card%5Bcvc%5D=)[^&]*)i, '\1[FILTERED]')
67
+ end
68
+
58
69
  private
59
70
 
60
71
  def add_order(post, money, options)
@@ -207,4 +218,3 @@ module ActiveMerchant #:nodoc:
207
218
  end
208
219
  end
209
220
  end
210
-
@@ -0,0 +1,208 @@
1
+ require 'nokogiri'
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+ class CreditcallGateway < Gateway
6
+ self.test_url = 'https://test.cardeasexml.com/generic.cex'
7
+ self.live_url = 'https://live.cardeasexml.com/'
8
+
9
+ self.supported_countries = ['US']
10
+ self.default_currency = 'USD'
11
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover]
12
+
13
+ self.homepage_url = 'https://www.creditcall.com'
14
+ self.display_name = 'Creditcall'
15
+
16
+ def initialize(options={})
17
+ requires!(options, :terminal_id, :transaction_key)
18
+ super
19
+ end
20
+
21
+ def purchase(money, payment_method, options={})
22
+ multi_response = MultiResponse.run do |r|
23
+ r.process { authorize(money, payment_method, options) }
24
+ r.process { capture(money, r.authorization, options) }
25
+ end
26
+
27
+ Response.new(
28
+ multi_response.primary_response.success?,
29
+ multi_response.primary_response.message,
30
+ multi_response.primary_response.params,
31
+ authorization: multi_response.responses.first.authorization,
32
+ test: test?
33
+ )
34
+ end
35
+
36
+ def authorize(money, payment_method, options={})
37
+ request = build_xml_request do |xml|
38
+ add_transaction_details(xml, money, nil, "Auth", options)
39
+ add_terminal_details(xml, options)
40
+ add_card_details(xml, payment_method, options)
41
+ end
42
+
43
+ commit(request)
44
+ end
45
+
46
+ def capture(money, authorization, options={})
47
+ request = build_xml_request do |xml|
48
+ add_transaction_details(xml, money, authorization, "Conf", options)
49
+ add_terminal_details(xml, options)
50
+ end
51
+
52
+ commit(request)
53
+ end
54
+
55
+ def refund(money, authorization, options={})
56
+ request = build_xml_request do |xml|
57
+ add_transaction_details(xml, money, authorization, "Refund", options)
58
+ add_terminal_details(xml, options)
59
+ end
60
+
61
+ commit(request)
62
+ end
63
+
64
+ def void(authorization, options={})
65
+ request = build_xml_request do |xml|
66
+ add_transaction_details(xml, nil, authorization, "Void", options)
67
+ add_terminal_details(xml, options)
68
+ end
69
+
70
+ commit(request)
71
+ end
72
+
73
+ def verify(credit_card, options={})
74
+ MultiResponse.run(:use_first_response) do |r|
75
+ r.process { authorize(100, credit_card, options) }
76
+ r.process(:ignore_result) { void(r.authorization, options) }
77
+ end
78
+ end
79
+
80
+ def supports_scrubbing?
81
+ true
82
+ end
83
+
84
+ def scrub(transcript)
85
+ transcript.
86
+ gsub(%r((<TransactionKey>).+?(</TransactionKey>))i, '\1[FILTERED]\2').
87
+ gsub(%r((<PAN>).+?(</PAN>))i, '\1[FILTERED]\2').
88
+ gsub(%r((<CSC>).+?(</CSC>))i, '\1[FILTERED]\2')
89
+ end
90
+
91
+ private
92
+
93
+ def build_xml_request
94
+ builder = Nokogiri::XML::Builder.new do |xml|
95
+ xml.Request(type: "CardEaseXML", version: "1.0.0") do
96
+ yield(xml)
97
+ end
98
+ end
99
+ builder.to_xml
100
+ end
101
+
102
+ def add_transaction_details(xml, amount, authorization, type, options={})
103
+ xml.TransactionDetails do
104
+ xml.MessageType type
105
+ xml.Amount(unit: "Minor"){ xml.text(amount) } if amount
106
+ xml.CardEaseReference authorization if authorization
107
+ xml.VoidReason "01" if type == "Void"
108
+ end
109
+ end
110
+
111
+ def add_terminal_details(xml, options={})
112
+ xml.TerminalDetails do
113
+ xml.TerminalID @options[:terminal_id]
114
+ xml.TransactionKey @options[:transaction_key]
115
+ xml.Software(version: "SoftwareVersion"){ xml.text("SoftwareName") }
116
+ end
117
+ end
118
+
119
+ def add_card_details(xml, payment_method, options={})
120
+ xml.CardDetails do
121
+ xml.Manual(type: "cnp") do
122
+ xml.PAN payment_method.number
123
+ xml.ExpiryDate exp_date(payment_method)
124
+ xml.CSC payment_method.verification_value
125
+ end
126
+
127
+ if address = options[:billing_address]
128
+ xml.AdditionalVerification do
129
+ xml.Address address[:address1]
130
+ xml.Zip address[:zip]
131
+ end
132
+ end
133
+ end
134
+ end
135
+
136
+ def exp_date(payment_method)
137
+ "#{format(payment_method.year, :two_digits)}#{format(payment_method.month, :two_digits)}"
138
+ end
139
+
140
+ def parse(body)
141
+ response = {}
142
+ xml = Nokogiri::XML(body)
143
+
144
+ node = xml.xpath("//Response/TransactionDetails")
145
+ node.children.each do |childnode|
146
+ response[childnode.name] = childnode.text
147
+ end
148
+
149
+ node = xml.xpath("//Response/Result")
150
+ node.children.each do |childnode|
151
+ if childnode.elements.empty?
152
+ response[childnode.name] = childnode.text
153
+ else
154
+ childnode_to_response(response, childnode)
155
+ end
156
+ end
157
+
158
+ response
159
+ end
160
+
161
+ def childnode_to_response(response, childnode)
162
+ childnode.elements.each do |element|
163
+ if element.name == "Error"
164
+ response["ErrorCode"] = element.attr("code")
165
+ response["ErrorMessage"] = element.text
166
+ else
167
+ response[element.name] = element.text
168
+ end
169
+ end
170
+ end
171
+
172
+ def commit(parameters)
173
+ response = parse(ssl_post(url, parameters))
174
+
175
+ Response.new(
176
+ success_from(response),
177
+ message_from(response),
178
+ response,
179
+ authorization: authorization_from(response),
180
+ avs_result: AVSResult.new(code: response["some_avs_response_key"]),
181
+ cvv_result: CVVResult.new(response["some_cvv_response_key"]),
182
+ test: test?
183
+ )
184
+ end
185
+
186
+ def url
187
+ test? ? test_url : live_url
188
+ end
189
+
190
+ def success_from(response)
191
+ response["LocalResult"] == "0" || response["LocalResult"] == "00"
192
+ end
193
+
194
+ def message_from(response)
195
+ if success_from(response)
196
+ "Succeeded"
197
+ else
198
+ response["ErrorMessage"]
199
+ end
200
+ end
201
+
202
+ def authorization_from(response)
203
+ response["CardEaseReference"]
204
+ end
205
+
206
+ end
207
+ end
208
+ end