activemerchant 1.52.0 → 1.53.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.
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