activemerchant 1.106.0 → 1.108.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 (52) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +79 -0
  3. data/README.md +2 -2
  4. data/lib/active_merchant/billing/gateways/adyen.rb +1 -1
  5. data/lib/active_merchant/billing/gateways/authorize_net.rb +1 -1
  6. data/lib/active_merchant/billing/gateways/blue_pay.rb +2 -2
  7. data/lib/active_merchant/billing/gateways/borgun.rb +15 -4
  8. data/lib/active_merchant/billing/gateways/braintree_blue.rb +11 -9
  9. data/lib/active_merchant/billing/gateways/checkout_v2.rb +20 -9
  10. data/lib/active_merchant/billing/gateways/clearhaus.rb +1 -1
  11. data/lib/active_merchant/billing/gateways/cyber_source.rb +74 -21
  12. data/lib/active_merchant/billing/gateways/d_local.rb +17 -5
  13. data/lib/active_merchant/billing/gateways/decidir.rb +29 -0
  14. data/lib/active_merchant/billing/gateways/ebanx.rb +13 -1
  15. data/lib/active_merchant/billing/gateways/elavon.rb +58 -5
  16. data/lib/active_merchant/billing/gateways/element.rb +13 -5
  17. data/lib/active_merchant/billing/gateways/firstdata_e4.rb +2 -2
  18. data/lib/active_merchant/billing/gateways/firstdata_e4_v27.rb +2 -2
  19. data/lib/active_merchant/billing/gateways/forte.rb +7 -6
  20. data/lib/active_merchant/billing/gateways/global_collect.rb +30 -24
  21. data/lib/active_merchant/billing/gateways/hps.rb +4 -2
  22. data/lib/active_merchant/billing/gateways/iats_payments.rb +31 -14
  23. data/lib/active_merchant/billing/gateways/iridium.rb +4 -2
  24. data/lib/active_merchant/billing/gateways/iveri.rb +4 -1
  25. data/lib/active_merchant/billing/gateways/ixopay.rb +1 -0
  26. data/lib/active_merchant/billing/gateways/kushki.rb +34 -5
  27. data/lib/active_merchant/billing/gateways/litle.rb +6 -1
  28. data/lib/active_merchant/billing/gateways/mercado_pago.rb +1 -0
  29. data/lib/active_merchant/billing/gateways/netaxept.rb +1 -1
  30. data/lib/active_merchant/billing/gateways/netbanx.rb +1 -1
  31. data/lib/active_merchant/billing/gateways/opp.rb +13 -7
  32. data/lib/active_merchant/billing/gateways/optimal_payment.rb +4 -0
  33. data/lib/active_merchant/billing/gateways/orbital.rb +44 -2
  34. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +1 -1
  35. data/lib/active_merchant/billing/gateways/payment_express.rb +2 -2
  36. data/lib/active_merchant/billing/gateways/payu_latam.rb +1 -1
  37. data/lib/active_merchant/billing/gateways/pin.rb +1 -1
  38. data/lib/active_merchant/billing/gateways/quantum.rb +1 -1
  39. data/lib/active_merchant/billing/gateways/realex.rb +10 -3
  40. data/lib/active_merchant/billing/gateways/redsys.rb +1 -1
  41. data/lib/active_merchant/billing/gateways/secure_pay_au.rb +1 -1
  42. data/lib/active_merchant/billing/gateways/so_easy_pay.rb +1 -1
  43. data/lib/active_merchant/billing/gateways/stripe.rb +7 -2
  44. data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +40 -6
  45. data/lib/active_merchant/billing/gateways/transact_pro.rb +2 -2
  46. data/lib/active_merchant/billing/gateways/trexle.rb +1 -1
  47. data/lib/active_merchant/billing/gateways/worldpay.rb +8 -6
  48. data/lib/active_merchant/billing/network_tokenization_credit_card.rb +1 -1
  49. data/lib/active_merchant/connection.rb +40 -42
  50. data/lib/active_merchant/network_connection_retries.rb +10 -12
  51. data/lib/active_merchant/version.rb +1 -1
  52. metadata +5 -4
@@ -21,6 +21,8 @@ module ActiveMerchant #:nodoc:
21
21
  visa: 'Visa 3DSecure',
22
22
  american_express: 'AMEX 3DSecure',
23
23
  discover: 'Discover 3DSecure',
24
+ android_pay: 'GooglePayApp',
25
+ google_pay: 'GooglePayApp'
24
26
  }
25
27
 
26
28
  def initialize(options={})
@@ -199,9 +201,9 @@ module ActiveMerchant #:nodoc:
199
201
  xml.hps :RoutingNumber, check.routing_number
200
202
  xml.hps :AccountNumber, check.account_number
201
203
  xml.hps :CheckNumber, check.number
202
- xml.hps :AccountType, check.account_type.upcase
204
+ xml.hps :AccountType, check.account_type&.upcase
203
205
  end
204
- xml.hps :CheckType, check.account_holder_type.upcase
206
+ xml.hps :CheckType, check.account_holder_type&.upcase
205
207
  end
206
208
 
207
209
  def add_details(xml, options)
@@ -14,12 +14,13 @@ module ActiveMerchant #:nodoc:
14
14
  self.display_name = 'iATS Payments'
15
15
 
16
16
  ACTIONS = {
17
- purchase: 'ProcessCreditCardV1',
18
- purchase_check: 'ProcessACHEFTV1',
19
- refund: 'ProcessCreditCardRefundWithTransactionIdV1',
20
- refund_check: 'ProcessACHEFTRefundWithTransactionIdV1',
21
- store: 'CreateCreditCardCustomerCodeV1',
22
- unstore: 'DeleteCustomerCodeV1'
17
+ purchase: 'ProcessCreditCard',
18
+ purchase_check: 'ProcessACHEFT',
19
+ purchase_customer_code: 'ProcessCreditCardWithCustomerCode',
20
+ refund: 'ProcessCreditCardRefundWithTransactionId',
21
+ refund_check: 'ProcessACHEFTRefundWithTransactionId',
22
+ store: 'CreateCreditCardCustomerCode',
23
+ unstore: 'DeleteCustomerCode'
23
24
  }
24
25
 
25
26
  def initialize(options={})
@@ -42,7 +43,7 @@ module ActiveMerchant #:nodoc:
42
43
  add_ip(post, options)
43
44
  add_description(post, options)
44
45
 
45
- commit((payment.is_a?(Check) ? :purchase_check : :purchase), post)
46
+ commit(determine_purchase_type(payment), post)
46
47
  end
47
48
 
48
49
  def refund(money, authorization, options={})
@@ -90,6 +91,16 @@ module ActiveMerchant #:nodoc:
90
91
 
91
92
  private
92
93
 
94
+ def determine_purchase_type(payment)
95
+ if payment.is_a?(String)
96
+ :purchase_customer_code
97
+ elsif payment.is_a?(Check)
98
+ :purchase_check
99
+ else
100
+ :purchase
101
+ end
102
+ end
103
+
93
104
  def add_ip(post, options)
94
105
  post[:customer_ip_address] = options[:ip] if options.has_key?(:ip)
95
106
  end
@@ -101,6 +112,9 @@ module ActiveMerchant #:nodoc:
101
112
  post[:city] = billing_address[:city]
102
113
  post[:state] = billing_address[:state]
103
114
  post[:zip_code] = billing_address[:zip]
115
+ post[:phone] = billing_address[:phone] if billing_address[:phone]
116
+ post[:email] = billing_address[:email] if billing_address[:email]
117
+ post[:country] = billing_address[:country] if billing_address[:country]
104
118
  end
105
119
  end
106
120
 
@@ -114,7 +128,9 @@ module ActiveMerchant #:nodoc:
114
128
  end
115
129
 
116
130
  def add_payment(post, payment)
117
- if payment.is_a?(Check)
131
+ if payment.is_a?(String)
132
+ post[:customer_code] = payment
133
+ elsif payment.is_a?(Check)
118
134
  add_check(post, payment)
119
135
  else
120
136
  add_credit_card(post, payment)
@@ -178,12 +194,13 @@ module ActiveMerchant #:nodoc:
178
194
 
179
195
  def endpoints
180
196
  {
181
- purchase: 'ProcessLink.asmx',
182
- purchase_check: 'ProcessLink.asmx',
183
- refund: 'ProcessLink.asmx',
184
- refund_check: 'ProcessLink.asmx',
185
- store: 'CustomerLink.asmx',
186
- unstore: 'CustomerLink.asmx'
197
+ purchase: 'ProcessLinkv3.asmx',
198
+ purchase_check: 'ProcessLinkv3.asmx',
199
+ purchase_customer_code: 'ProcessLinkv3.asmx',
200
+ refund: 'ProcessLinkv3.asmx',
201
+ refund_check: 'ProcessLinkv3.asmx',
202
+ store: 'CustomerLinkv3.asmx',
203
+ unstore: 'CustomerLinkv3.asmx'
187
204
  }
188
205
  end
189
206
 
@@ -291,7 +291,8 @@ module ActiveMerchant #:nodoc:
291
291
  order_id, cross_reference, _ = authorization.split(';')
292
292
  build_request(options) do |xml|
293
293
  if money
294
- details = {'CurrencyCode' => currency_code(options[:currency] || default_currency), 'Amount' => amount(money)}
294
+ currency = options[:currency] || currency(money)
295
+ details = {'CurrencyCode' => currency_code(currency), 'Amount' => localized_amount(money, currency)}
295
296
  else
296
297
  details = {'CurrencyCode' => currency_code(default_currency), 'Amount' => '0'}
297
298
  end
@@ -327,8 +328,9 @@ module ActiveMerchant #:nodoc:
327
328
  end
328
329
 
329
330
  def add_purchase_data(xml, type, money, options)
331
+ currency = options[:currency] || currency(money)
330
332
  requires!(options, :order_id)
331
- xml.tag! 'TransactionDetails', {'Amount' => amount(money), 'CurrencyCode' => currency_code(options[:currency] || currency(money))} do
333
+ xml.tag! 'TransactionDetails', {'Amount' => localized_amount(money, currency), 'CurrencyCode' => currency_code(currency)} do
332
334
  xml.tag! 'MessageDetails', {'TransactionType' => type}
333
335
  xml.tag! 'OrderID', options[:order_id]
334
336
  xml.tag! 'TransactionControl' do
@@ -60,7 +60,10 @@ module ActiveMerchant #:nodoc:
60
60
  end
61
61
 
62
62
  def verify(credit_card, options={})
63
- authorize(0, credit_card, options)
63
+ MultiResponse.run(:use_first_response) do |r|
64
+ r.process { authorize(100, credit_card, options) }
65
+ r.process(:ignore_result) { void(r.authorization, options) }
66
+ end
64
67
  end
65
68
 
66
69
  def verify_credentials
@@ -8,6 +8,7 @@ module ActiveMerchant #:nodoc:
8
8
 
9
9
  self.supported_countries = %w(AO AQ AR AS AT AU AW AX AZ BA BB BD BE BF BG BH BI BJ BL BM BN BO BQ BQ BR BS BT BV BW BY BZ CA CC CD CF CG CH CI CK CL CM CN CO CR CU CV CW CX CY CZ DE DJ DK DM DO DZ EC EE EG EH ER ES ET FI FJ FK FM FO FR GA GB GD GE GF GG GH GI GL GM GN GP GQ GR GS GT GU GW GY HK HM HN HR HT HU ID IE IL IM IN IO IQ IR IS IT JE JM JO JP KE KG KH KI KM KN KP KR KW KY KZ LA LB LC LI LK LR LS LT LU LV LY MA MC MD ME MF MG MH MK ML MM MN MO MP MQ MR MS MT MU MV MW MX MY MZ NA NC NE NF NG NI NL NO NP NR NU NZ OM PA PE PF PG PH PK PL PM PN PR PS PT PW PY QA RE RO RS RU RW SA SB SC SD SE SG SH SI SJ SK SL SM SN SO SR SS ST SV SX SY SZ TC TD TF TG TH TJ TK TL TM TN TO TR TT TV TW TZ UA UG UM US UY UZ VA VC VE VG VI VN VU WF WS YE YT ZA ZM ZW)
10
10
  self.default_currency = 'EUR'
11
+ self.currencies_with_three_decimal_places = %w(BHD IQD JOD KWD LWD OMR TND)
11
12
  self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb, :maestro]
12
13
 
13
14
  self.homepage_url = 'https://www.ixopay.com'
@@ -4,8 +4,8 @@ module ActiveMerchant #:nodoc:
4
4
  self.display_name = 'Kushki'
5
5
  self.homepage_url = 'https://www.kushkipagos.com'
6
6
 
7
- self.test_url = 'https://api-uat.kushkipagos.com/v1/'
8
- self.live_url = 'https://api.kushkipagos.com/v1/'
7
+ self.test_url = 'https://api-uat.kushkipagos.com/'
8
+ self.live_url = 'https://api.kushkipagos.com/'
9
9
 
10
10
  self.supported_countries = ['CL', 'CO', 'EC', 'MX', 'PE']
11
11
  self.default_currency = 'USD'
@@ -24,6 +24,23 @@ module ActiveMerchant #:nodoc:
24
24
  end
25
25
  end
26
26
 
27
+ def authorize(amount, payment_method, options={})
28
+ MultiResponse.run() do |r|
29
+ r.process { tokenize(amount, payment_method, options) }
30
+ r.process { preauthorize(amount, r.authorization, options) }
31
+ end
32
+ end
33
+
34
+ def capture(amount, authorization, options={})
35
+ action = 'capture'
36
+
37
+ post = {}
38
+ post[:ticketNumber] = authorization
39
+ add_invoice(action, post, amount, options)
40
+
41
+ commit(action, post)
42
+ end
43
+
27
44
  def refund(amount, authorization, options={})
28
45
  action = 'refund'
29
46
 
@@ -75,6 +92,16 @@ module ActiveMerchant #:nodoc:
75
92
  commit(action, post)
76
93
  end
77
94
 
95
+ def preauthorize(amount, authorization, options)
96
+ action = 'preAuthorization'
97
+
98
+ post = {}
99
+ add_reference(post, authorization, options)
100
+ add_invoice(action, post, amount, options)
101
+
102
+ commit(action, post)
103
+ end
104
+
78
105
  def add_invoice(action, post, money, options)
79
106
  if action == 'tokenize'
80
107
  post[:totalAmount] = amount(money).to_f
@@ -131,7 +158,9 @@ module ActiveMerchant #:nodoc:
131
158
  'tokenize' => 'tokens',
132
159
  'charge' => 'charges',
133
160
  'void' => 'charges',
134
- 'refund' => 'refund'
161
+ 'refund' => 'refund',
162
+ 'preAuthorization' => 'preAuthorization',
163
+ 'capture' => 'capture'
135
164
  }
136
165
 
137
166
  def commit(action, params)
@@ -178,9 +207,9 @@ module ActiveMerchant #:nodoc:
178
207
  base_url = test? ? test_url : live_url
179
208
 
180
209
  if ['void', 'refund'].include?(action)
181
- base_url + ENDPOINT[action] + '/' + params[:ticketNumber].to_s
210
+ base_url + 'v1/' + ENDPOINT[action] + '/' + params[:ticketNumber].to_s
182
211
  else
183
- base_url + ENDPOINT[action]
212
+ base_url + 'card/v1/' + ENDPOINT[action]
184
213
  end
185
214
  end
186
215
 
@@ -263,6 +263,7 @@ module ActiveMerchant #:nodoc:
263
263
  if payment_method.is_a?(String)
264
264
  doc.token do
265
265
  doc.litleToken(payment_method)
266
+ doc.expDate(format_exp_date(options[:basis_expiration_month], options[:basis_expiration_year])) if options[:basis_expiration_month] && options[:basis_expiration_year]
266
267
  end
267
268
  elsif payment_method.respond_to?(:track_data) && payment_method.track_data.present?
268
269
  doc.card do
@@ -416,7 +417,11 @@ module ActiveMerchant #:nodoc:
416
417
  end
417
418
 
418
419
  def exp_date(payment_method)
419
- "#{format(payment_method.month, :two_digits)}#{format(payment_method.year, :two_digits)}"
420
+ format_exp_date(payment_method.month, payment_method.year)
421
+ end
422
+
423
+ def format_exp_date(month, year)
424
+ "#{format(month, :two_digits)}#{format(year, :two_digits)}"
420
425
  end
421
426
 
422
427
  def parse(kind, xml)
@@ -113,6 +113,7 @@ module ActiveMerchant #:nodoc:
113
113
 
114
114
  post[:processing_mode] = options[:processing_mode]
115
115
  post[:merchant_account_id] = options[:merchant_account_id] if options[:merchant_account_id]
116
+ post[:payment_method_option_id] = options[:payment_method_option_id] if options[:payment_method_option_id]
116
117
  add_merchant_services(post, options)
117
118
  end
118
119
 
@@ -123,7 +123,7 @@ module ActiveMerchant #:nodoc:
123
123
 
124
124
  success = false
125
125
  authorization = (raw['TransactionId'] || parameters[:transactionId])
126
- if raw[:container] =~ /Exception|Error/
126
+ if /Exception|Error/.match?(raw[:container])
127
127
  message = (raw['Message'] || raw['Error']['Message'])
128
128
  elsif raw['Error'] && !raw['Error'].empty?
129
129
  message = (raw['Error']['ResponseText'] || raw['Error']['ResponseCode'])
@@ -222,7 +222,7 @@ module ActiveMerchant #:nodoc:
222
222
 
223
223
  def get_url(uri)
224
224
  url = (test? ? test_url : live_url)
225
- if uri =~ /^customervault/
225
+ if /^customervault/.match?(uri)
226
226
  "#{url}#{uri}"
227
227
  else
228
228
  "#{url}cardpayments/v1/accounts/#{@options[:account_number]}/#{uri}"
@@ -13,8 +13,7 @@ module ActiveMerchant #:nodoc:
13
13
  # == Usage
14
14
  #
15
15
  # gateway = ActiveMerchant::Billing::OppGateway.new(
16
- # user_id: 'merchant user id',
17
- # password: 'password',
16
+ # access_token: 'access_token',
18
17
  # entity_id: 'entity id',
19
18
  # )
20
19
  #
@@ -119,7 +118,7 @@ module ActiveMerchant #:nodoc:
119
118
  self.display_name = 'Open Payment Platform'
120
119
 
121
120
  def initialize(options={})
122
- requires!(options, :user_id, :password, :entity_id)
121
+ requires!(options, :access_token, :entity_id)
123
122
  super
124
123
  end
125
124
 
@@ -167,7 +166,7 @@ module ActiveMerchant #:nodoc:
167
166
 
168
167
  def scrub(transcript)
169
168
  transcript.
170
- gsub(%r((authentication\.password=)\w+), '\1[FILTERED]').
169
+ gsub(%r((Authorization: Bearer )\w+)i, '\1[FILTERED]').
171
170
  gsub(%r((card\.number=)\d+), '\1[FILTERED]').
172
171
  gsub(%r((card\.cvv=)\d+), '\1[FILTERED]')
173
172
  end
@@ -203,7 +202,7 @@ module ActiveMerchant #:nodoc:
203
202
  end
204
203
 
205
204
  def add_authentication(post)
206
- post[:authentication] = { entityId: @options[:entity_id], password: @options[:password], userId: @options[:user_id]}
205
+ post[:authentication] = { entityId: @options[:entity_id] }
207
206
  end
208
207
 
209
208
  def add_customer_data(post, payment, options)
@@ -316,7 +315,7 @@ module ActiveMerchant #:nodoc:
316
315
  ssl_post(
317
316
  url,
318
317
  post.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join('&'),
319
- 'Content-Type' => 'application/x-www-form-urlencoded;charset=UTF-8'
318
+ headers
320
319
  )
321
320
  )
322
321
  rescue ResponseError => e
@@ -335,6 +334,13 @@ module ActiveMerchant #:nodoc:
335
334
  )
336
335
  end
337
336
 
337
+ def headers
338
+ {
339
+ 'Content-Type' => 'application/x-www-form-urlencoded;charset=UTF-8',
340
+ 'Authorization' => "Bearer #{@options[:access_token]}"
341
+ }
342
+ end
343
+
338
344
  def parse(body)
339
345
  JSON.parse(body)
340
346
  rescue JSON::ParserError
@@ -351,7 +357,7 @@ module ActiveMerchant #:nodoc:
351
357
 
352
358
  success_regex = /^(000\.000\.|000\.100\.1|000\.[36])/
353
359
 
354
- if success_regex =~ response['result']['code']
360
+ if success_regex.match?(response['result']['code'])
355
361
  true
356
362
  else
357
363
  false
@@ -65,6 +65,10 @@ module ActiveMerchant #:nodoc:
65
65
  commit('ccVerification', 0, options)
66
66
  end
67
67
 
68
+ def store(credit_card, options = {})
69
+ verify(credit_card, options)
70
+ end
71
+
68
72
  def supports_scrubbing?
69
73
  true
70
74
  end
@@ -306,7 +306,8 @@ module ActiveMerchant #:nodoc:
306
306
  gsub(%r((<OrbitalConnectionUsername>).+(</OrbitalConnectionUsername>)), '\1[FILTERED]\2').
307
307
  gsub(%r((<OrbitalConnectionPassword>).+(</OrbitalConnectionPassword>)), '\1[FILTERED]\2').
308
308
  gsub(%r((<AccountNum>).+(</AccountNum>)), '\1[FILTERED]\2').
309
- gsub(%r((<CCAccountNum>).+(</CCAccountNum>)), '\1[FILTERED]\2').
309
+ # the response sometimes contains a new line that cuts off the end of the closing tag
310
+ gsub(%r((<CCAccountNum>).+(</CC)), '\1[FILTERED]\2').
310
311
  gsub(%r((<CardSecVal>).+(</CardSecVal>)), '\1[FILTERED]\2').
311
312
  gsub(%r((<MerchantID>).+(</MerchantID>)), '\1[FILTERED]\2').
312
313
  gsub(%r((<CustomerMerchantID>).+(</CustomerMerchantID>)), '\1[FILTERED]\2')
@@ -361,6 +362,15 @@ module ActiveMerchant #:nodoc:
361
362
  end
362
363
  end
363
364
 
365
+ def add_level_3_tax(xml, options={})
366
+ if (level_3 = options[:level_3_data])
367
+ xml.tag! :PC3VATtaxAmt, byte_limit(level_3[:vat_tax], 12) if level_3[:vat_tax]
368
+ xml.tag! :PC3AltTaxAmt, byte_limit(level_3[:alt_tax], 9) if level_3[:alt_tax]
369
+ xml.tag! :PC3VATtaxRate, byte_limit(level_3[:vat_rate], 4) if level_3[:vat_rate]
370
+ xml.tag! :PC3AltTaxInd, byte_limit(level_3[:alt_ind], 15) if level_3[:alt_ind]
371
+ end
372
+ end
373
+
364
374
  def add_level_2_advice_addendum(xml, options={})
365
375
  if (level_2 = options[:level_2_data])
366
376
  xml.tag! :AMEXTranAdvAddn1, byte_limit(level_2[:advice_addendum_1], 40) if level_2[:advice_addendum_1]
@@ -382,6 +392,35 @@ module ActiveMerchant #:nodoc:
382
392
  end
383
393
  end
384
394
 
395
+ def add_level_3_purchase(xml, options={})
396
+ if (level_3 = options[:level_3_data])
397
+ xml.tag! :PC3FreightAmt, byte_limit(level_3[:freight_amount], 12) if level_3[:freight_amount]
398
+ xml.tag! :PC3DutyAmt, byte_limit(level_3[:duty_amount], 12) if level_3[:duty_amount]
399
+ xml.tag! :PC3DestCountryCd, byte_limit(level_3[:dest_country], 3) if level_3[:dest_country]
400
+ xml.tag! :PC3ShipFromZip, byte_limit(level_3[:ship_from_zip], 10) if level_3[:ship_from_zip]
401
+ xml.tag! :PC3DiscAmt, byte_limit(level_3[:discount_amount], 12) if level_3[:discount_amount]
402
+ end
403
+ end
404
+
405
+ def add_line_items(xml, options={})
406
+ xml.tag! :PC3LineItemCount, byte_limit(options[:line_items].count, 2)
407
+ xml.tag! :PC3LineItemArray do
408
+ options[:line_items].each_with_index do |line_item, index|
409
+ xml.tag! :PC3LineItem do
410
+ xml.tag! :PC3DtlIndex, byte_limit(index + 1, 2)
411
+ line_item.each do |key, value|
412
+ if key == :line_tot
413
+ formatted_key = :PC3Dtllinetot
414
+ else
415
+ formatted_key = "PC3Dtl#{key.to_s.camelize}".to_sym
416
+ end
417
+ xml.tag! formatted_key, value
418
+ end
419
+ end
420
+ end
421
+ end
422
+ end
423
+
385
424
  def add_address(xml, creditcard, options)
386
425
  if (address = (options[:billing_address] || options[:address]))
387
426
  avs_supported = AVS_SUPPORTED_COUNTRIES.include?(address[:country].to_s) || empty?(address[:country])
@@ -569,7 +608,7 @@ module ActiveMerchant #:nodoc:
569
608
 
570
609
  initiator =
571
610
  case parameters[:stored_credential][:initiator]
572
- when 'customer' then 'C'
611
+ when 'cardholder', 'customer' then 'C'
573
612
  when 'merchant' then 'M'
574
613
  end
575
614
  reason =
@@ -715,6 +754,9 @@ module ActiveMerchant #:nodoc:
715
754
  end
716
755
 
717
756
  add_level_2_purchase(xml, parameters)
757
+ add_level_3_purchase(xml, parameters)
758
+ add_level_3_tax(xml, parameters)
759
+ add_line_items(xml, parameters) if parameters[:line_items]
718
760
  add_stored_credentials(xml, parameters)
719
761
  add_pymt_brand_program_code(xml, creditcard, three_d_secure)
720
762
  end
@@ -181,7 +181,7 @@ module ActiveMerchant #:nodoc:
181
181
  node.xpath('.//*').each { |e| parse_element(payment_result_response, e) }
182
182
  when node.xpath('.//*').to_a.any?
183
183
  node.xpath('.//*').each { |e| parse_element(response, e) }
184
- when node_name.to_s =~ /amt$/
184
+ when /amt$/.match?(node_name.to_s)
185
185
  # *Amt elements don't put the value in the #text - instead they use a Currency attribute
186
186
  response[node_name] = node.attributes['Currency'].to_s
187
187
  when node_name == :ext_data
@@ -17,8 +17,8 @@ module ActiveMerchant #:nodoc:
17
17
 
18
18
  self.supported_countries = %w[AU FJ GB HK IE MY NZ PG SG US]
19
19
 
20
- self.homepage_url = 'http://www.paymentexpress.com/'
21
- self.display_name = 'PaymentExpress'
20
+ self.homepage_url = 'https://www.windcave.com/'
21
+ self.display_name = 'Windcave (formerly PaymentExpress)'
22
22
 
23
23
  self.live_url = 'https://sec.paymentexpress.com/pxpost.aspx'
24
24
  self.test_url = 'https://uat.paymentexpress.com/pxpost.aspx'