activemerchant 1.130.0 → 1.137.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (184) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +268 -0
  3. data/lib/active_merchant/billing/check.rb +2 -2
  4. data/lib/active_merchant/billing/compatibility.rb +4 -4
  5. data/lib/active_merchant/billing/credit_card.rb +13 -8
  6. data/lib/active_merchant/billing/credit_card_formatting.rb +4 -0
  7. data/lib/active_merchant/billing/credit_card_methods.rb +64 -7
  8. data/lib/active_merchant/billing/gateway.rb +9 -0
  9. data/lib/active_merchant/billing/gateways/adyen.rb +240 -41
  10. data/lib/active_merchant/billing/gateways/airwallex.rb +26 -12
  11. data/lib/active_merchant/billing/gateways/alelo.rb +23 -5
  12. data/lib/active_merchant/billing/gateways/authorize_net.rb +44 -36
  13. data/lib/active_merchant/billing/gateways/authorize_net_arb.rb +10 -6
  14. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +1 -3
  15. data/lib/active_merchant/billing/gateways/axcessms.rb +6 -2
  16. data/lib/active_merchant/billing/gateways/banwire.rb +4 -2
  17. data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +7 -3
  18. data/lib/active_merchant/billing/gateways/blue_pay.rb +13 -5
  19. data/lib/active_merchant/billing/gateways/blue_snap.rb +5 -5
  20. data/lib/active_merchant/billing/gateways/borgun.rb +6 -4
  21. data/lib/active_merchant/billing/gateways/braintree/token_nonce.rb +65 -20
  22. data/lib/active_merchant/billing/gateways/braintree_blue.rb +226 -73
  23. data/lib/active_merchant/billing/gateways/braintree_orange.rb +1 -1
  24. data/lib/active_merchant/billing/gateways/card_connect.rb +5 -2
  25. data/lib/active_merchant/billing/gateways/card_stream.rb +4 -6
  26. data/lib/active_merchant/billing/gateways/cashnet.rb +1 -1
  27. data/lib/active_merchant/billing/gateways/cecabank/cecabank_common.rb +36 -0
  28. data/lib/active_merchant/billing/gateways/cecabank/cecabank_json.rb +316 -0
  29. data/lib/active_merchant/billing/gateways/cecabank/cecabank_xml.rb +220 -0
  30. data/lib/active_merchant/billing/gateways/cecabank.rb +7 -240
  31. data/lib/active_merchant/billing/gateways/checkout_v2.rb +252 -41
  32. data/lib/active_merchant/billing/gateways/commerce_hub.rb +69 -8
  33. data/lib/active_merchant/billing/gateways/credorax.rb +3 -5
  34. data/lib/active_merchant/billing/gateways/cyber_source.rb +192 -41
  35. data/lib/active_merchant/billing/gateways/cyber_source_rest.rb +102 -58
  36. data/lib/active_merchant/billing/gateways/d_local.rb +26 -15
  37. data/lib/active_merchant/billing/gateways/data_cash.rb +21 -17
  38. data/lib/active_merchant/billing/gateways/datatrans.rb +279 -0
  39. data/lib/active_merchant/billing/gateways/decidir.rb +53 -18
  40. data/lib/active_merchant/billing/gateways/decidir_plus.rb +4 -1
  41. data/lib/active_merchant/billing/gateways/deepstack.rb +382 -0
  42. data/lib/active_merchant/billing/gateways/ebanx.rb +40 -36
  43. data/lib/active_merchant/billing/gateways/efsnet.rb +6 -2
  44. data/lib/active_merchant/billing/gateways/elavon.rb +99 -33
  45. data/lib/active_merchant/billing/gateways/element.rb +36 -7
  46. data/lib/active_merchant/billing/gateways/epay.rb +6 -2
  47. data/lib/active_merchant/billing/gateways/evo_ca.rb +6 -2
  48. data/lib/active_merchant/billing/gateways/eway.rb +4 -2
  49. data/lib/active_merchant/billing/gateways/eway_managed.rb +6 -2
  50. data/lib/active_merchant/billing/gateways/exact.rb +6 -2
  51. data/lib/active_merchant/billing/gateways/fat_zebra.rb +31 -3
  52. data/lib/active_merchant/billing/gateways/federated_canada.rb +6 -2
  53. data/lib/active_merchant/billing/gateways/first_pay/first_pay_common.rb +15 -0
  54. data/lib/active_merchant/billing/gateways/first_pay/first_pay_json.rb +190 -0
  55. data/lib/active_merchant/billing/gateways/first_pay/first_pay_xml.rb +183 -0
  56. data/lib/active_merchant/billing/gateways/first_pay.rb +6 -172
  57. data/lib/active_merchant/billing/gateways/firstdata_e4.rb +6 -2
  58. data/lib/active_merchant/billing/gateways/firstdata_e4_v27.rb +7 -3
  59. data/lib/active_merchant/billing/gateways/flex_charge.rb +347 -0
  60. data/lib/active_merchant/billing/gateways/garanti.rb +4 -2
  61. data/lib/active_merchant/billing/gateways/global_collect.rb +45 -37
  62. data/lib/active_merchant/billing/gateways/hi_pay.rb +286 -0
  63. data/lib/active_merchant/billing/gateways/hps.rb +1 -1
  64. data/lib/active_merchant/billing/gateways/iats_payments.rb +7 -2
  65. data/lib/active_merchant/billing/gateways/inspire.rb +6 -4
  66. data/lib/active_merchant/billing/gateways/instapay.rb +7 -4
  67. data/lib/active_merchant/billing/gateways/ipg.rb +10 -6
  68. data/lib/active_merchant/billing/gateways/iridium.rb +15 -5
  69. data/lib/active_merchant/billing/gateways/itransact.rb +6 -2
  70. data/lib/active_merchant/billing/gateways/iveri.rb +3 -3
  71. data/lib/active_merchant/billing/gateways/ixopay.rb +2 -2
  72. data/lib/active_merchant/billing/gateways/jetpay.rb +4 -2
  73. data/lib/active_merchant/billing/gateways/jetpay_v2.rb +4 -2
  74. data/lib/active_merchant/billing/gateways/kushki.rb +73 -13
  75. data/lib/active_merchant/billing/gateways/linkpoint.rb +6 -2
  76. data/lib/active_merchant/billing/gateways/litle.rb +33 -50
  77. data/lib/active_merchant/billing/gateways/mastercard.rb +4 -4
  78. data/lib/active_merchant/billing/gateways/maxipago.rb +2 -2
  79. data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +8 -5
  80. data/lib/active_merchant/billing/gateways/merchant_ware.rb +11 -4
  81. data/lib/active_merchant/billing/gateways/merchant_ware_version_four.rb +11 -4
  82. data/lib/active_merchant/billing/gateways/merchant_warrior.rb +19 -3
  83. data/lib/active_merchant/billing/gateways/mercury.rb +6 -2
  84. data/lib/active_merchant/billing/gateways/metrics_global.rb +8 -6
  85. data/lib/active_merchant/billing/gateways/migs/migs_codes.rb +1 -0
  86. data/lib/active_merchant/billing/gateways/migs.rb +6 -2
  87. data/lib/active_merchant/billing/gateways/mit.rb +25 -20
  88. data/lib/active_merchant/billing/gateways/modern_payments_cim.rb +18 -10
  89. data/lib/active_merchant/billing/gateways/monei.rb +1 -1
  90. data/lib/active_merchant/billing/gateways/moneris.rb +9 -3
  91. data/lib/active_merchant/billing/gateways/money_movers.rb +6 -2
  92. data/lib/active_merchant/billing/gateways/nab_transact.rb +12 -4
  93. data/lib/active_merchant/billing/gateways/net_registry.rb +6 -2
  94. data/lib/active_merchant/billing/gateways/netbanx.rb +1 -3
  95. data/lib/active_merchant/billing/gateways/netbilling.rb +6 -2
  96. data/lib/active_merchant/billing/gateways/network_merchants.rb +6 -2
  97. data/lib/active_merchant/billing/gateways/nmi.rb +23 -6
  98. data/lib/active_merchant/billing/gateways/ogone.rb +6 -2
  99. data/lib/active_merchant/billing/gateways/openpay.rb +4 -2
  100. data/lib/active_merchant/billing/gateways/opp.rb +1 -2
  101. data/lib/active_merchant/billing/gateways/optimal_payment.rb +6 -2
  102. data/lib/active_merchant/billing/gateways/orbital/orbital_soft_descriptors.rb +1 -3
  103. data/lib/active_merchant/billing/gateways/orbital.rb +83 -24
  104. data/lib/active_merchant/billing/gateways/pac_net_raven.rb +7 -4
  105. data/lib/active_merchant/billing/gateways/pay_gate_xml.rb +6 -2
  106. data/lib/active_merchant/billing/gateways/pay_hub.rb +4 -2
  107. data/lib/active_merchant/billing/gateways/pay_junction.rb +6 -2
  108. data/lib/active_merchant/billing/gateways/pay_secure.rb +6 -2
  109. data/lib/active_merchant/billing/gateways/pay_trace.rb +31 -18
  110. data/lib/active_merchant/billing/gateways/payeezy.rb +19 -8
  111. data/lib/active_merchant/billing/gateways/payex.rb +4 -2
  112. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +1 -1
  113. data/lib/active_merchant/billing/gateways/payflow.rb +1 -3
  114. data/lib/active_merchant/billing/gateways/payment_express.rb +8 -4
  115. data/lib/active_merchant/billing/gateways/paymentez.rb +23 -11
  116. data/lib/active_merchant/billing/gateways/paysafe.rb +12 -11
  117. data/lib/active_merchant/billing/gateways/payscout.rb +7 -4
  118. data/lib/active_merchant/billing/gateways/paystation.rb +7 -3
  119. data/lib/active_merchant/billing/gateways/payway.rb +6 -2
  120. data/lib/active_merchant/billing/gateways/payway_dot_com.rb +3 -3
  121. data/lib/active_merchant/billing/gateways/pin.rb +22 -4
  122. data/lib/active_merchant/billing/gateways/plexo.rb +49 -10
  123. data/lib/active_merchant/billing/gateways/plugnpay.rb +6 -2
  124. data/lib/active_merchant/billing/gateways/priority.rb +6 -5
  125. data/lib/active_merchant/billing/gateways/psigate.rb +6 -2
  126. data/lib/active_merchant/billing/gateways/psl_card.rb +6 -2
  127. data/lib/active_merchant/billing/gateways/qbms.rb +6 -2
  128. data/lib/active_merchant/billing/gateways/quantum.rb +6 -2
  129. data/lib/active_merchant/billing/gateways/quickbooks.rb +6 -5
  130. data/lib/active_merchant/billing/gateways/quickpay/quickpay_v10.rb +7 -4
  131. data/lib/active_merchant/billing/gateways/quickpay/quickpay_v4to7.rb +6 -2
  132. data/lib/active_merchant/billing/gateways/rapyd.rb +148 -46
  133. data/lib/active_merchant/billing/gateways/reach.rb +11 -4
  134. data/lib/active_merchant/billing/gateways/redsys.rb +3 -11
  135. data/lib/active_merchant/billing/gateways/redsys_rest.rb +507 -0
  136. data/lib/active_merchant/billing/gateways/s5.rb +3 -3
  137. data/lib/active_merchant/billing/gateways/safe_charge.rb +38 -17
  138. data/lib/active_merchant/billing/gateways/sage.rb +12 -4
  139. data/lib/active_merchant/billing/gateways/sage_pay.rb +79 -5
  140. data/lib/active_merchant/billing/gateways/sallie_mae.rb +6 -2
  141. data/lib/active_merchant/billing/gateways/secure_net.rb +6 -2
  142. data/lib/active_merchant/billing/gateways/secure_pay.rb +8 -6
  143. data/lib/active_merchant/billing/gateways/secure_pay_au.rb +12 -4
  144. data/lib/active_merchant/billing/gateways/secure_pay_tech.rb +6 -2
  145. data/lib/active_merchant/billing/gateways/securion_pay.rb +24 -10
  146. data/lib/active_merchant/billing/gateways/shift4.rb +17 -20
  147. data/lib/active_merchant/billing/gateways/shift4_v2.rb +117 -0
  148. data/lib/active_merchant/billing/gateways/simetrik.rb +17 -11
  149. data/lib/active_merchant/billing/gateways/skip_jack.rb +6 -2
  150. data/lib/active_merchant/billing/gateways/smart_ps.rb +7 -4
  151. data/lib/active_merchant/billing/gateways/so_easy_pay.rb +4 -2
  152. data/lib/active_merchant/billing/gateways/spreedly_core.rb +2 -4
  153. data/lib/active_merchant/billing/gateways/stripe.rb +63 -19
  154. data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +280 -88
  155. data/lib/active_merchant/billing/gateways/sum_up.rb +223 -0
  156. data/lib/active_merchant/billing/gateways/swipe_checkout.rb +4 -2
  157. data/lib/active_merchant/billing/gateways/telr.rb +3 -4
  158. data/lib/active_merchant/billing/gateways/trans_first.rb +1 -2
  159. data/lib/active_merchant/billing/gateways/trans_first_transaction_express.rb +8 -16
  160. data/lib/active_merchant/billing/gateways/transact_pro.rb +1 -1
  161. data/lib/active_merchant/billing/gateways/trust_commerce.rb +6 -2
  162. data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +9 -8
  163. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +6 -2
  164. data/lib/active_merchant/billing/gateways/vanco.rb +2 -4
  165. data/lib/active_merchant/billing/gateways/vantiv_express.rb +587 -0
  166. data/lib/active_merchant/billing/gateways/verifi.rb +6 -2
  167. data/lib/active_merchant/billing/gateways/viaklix.rb +6 -2
  168. data/lib/active_merchant/billing/gateways/visanet_peru.rb +2 -2
  169. data/lib/active_merchant/billing/gateways/vpos.rb +4 -4
  170. data/lib/active_merchant/billing/gateways/wirecard.rb +7 -3
  171. data/lib/active_merchant/billing/gateways/wompi.rb +5 -0
  172. data/lib/active_merchant/billing/gateways/worldpay.rb +147 -93
  173. data/lib/active_merchant/billing/gateways/worldpay_online_payments.rb +13 -10
  174. data/lib/active_merchant/billing/gateways/xpay.rb +242 -0
  175. data/lib/active_merchant/billing/network_tokenization_credit_card.rb +1 -1
  176. data/lib/active_merchant/billing/response.rb +2 -2
  177. data/lib/active_merchant/connection.rb +3 -17
  178. data/lib/active_merchant/country.rb +1 -0
  179. data/lib/active_merchant/errors.rb +10 -0
  180. data/lib/active_merchant/version.rb +1 -1
  181. data/lib/support/gateway_support.rb +2 -2
  182. data/lib/support/ssl_verify.rb +4 -4
  183. data/lib/support/ssl_version.rb +6 -6
  184. metadata +30 -9
@@ -7,7 +7,7 @@ module ActiveMerchant #:nodoc:
7
7
  self.test_url = 'https://api-uat.kushkipagos.com/'
8
8
  self.live_url = 'https://api.kushkipagos.com/'
9
9
 
10
- self.supported_countries = %w[CL CO EC MX PE]
10
+ self.supported_countries = %w[BR CL CO EC MX PE]
11
11
  self.default_currency = 'USD'
12
12
  self.money_format = :dollars
13
13
  self.supported_cardtypes = %i[visa master american_express discover diners_club alia]
@@ -20,14 +20,14 @@ module ActiveMerchant #:nodoc:
20
20
  def purchase(amount, payment_method, options = {})
21
21
  MultiResponse.run() do |r|
22
22
  r.process { tokenize(amount, payment_method, options) }
23
- r.process { charge(amount, r.authorization, options) }
23
+ r.process { charge(amount, r.authorization, options, payment_method) }
24
24
  end
25
25
  end
26
26
 
27
27
  def authorize(amount, payment_method, options = {})
28
28
  MultiResponse.run() do |r|
29
29
  r.process { tokenize(amount, payment_method, options) }
30
- r.process { preauthorize(amount, r.authorization, options) }
30
+ r.process { preauthorize(amount, r.authorization, options, payment_method) }
31
31
  end
32
32
  end
33
33
 
@@ -48,8 +48,9 @@ module ActiveMerchant #:nodoc:
48
48
  post = {}
49
49
  post[:ticketNumber] = authorization
50
50
  add_full_response(post, options)
51
+ add_invoice(action, post, amount, options)
51
52
 
52
- commit(action, post)
53
+ commit(action, post, options)
53
54
  end
54
55
 
55
56
  def void(authorization, options = {})
@@ -89,7 +90,7 @@ module ActiveMerchant #:nodoc:
89
90
  commit(action, post)
90
91
  end
91
92
 
92
- def charge(amount, authorization, options)
93
+ def charge(amount, authorization, options, payment_method = {})
93
94
  action = 'charge'
94
95
 
95
96
  post = {}
@@ -100,11 +101,13 @@ module ActiveMerchant #:nodoc:
100
101
  add_metadata(post, options)
101
102
  add_months(post, options)
102
103
  add_deferred(post, options)
104
+ add_three_d_secure(post, payment_method, options)
105
+ add_product_details(post, options)
103
106
 
104
107
  commit(action, post)
105
108
  end
106
109
 
107
- def preauthorize(amount, authorization, options)
110
+ def preauthorize(amount, authorization, options, payment_method = {})
108
111
  action = 'preAuthorization'
109
112
 
110
113
  post = {}
@@ -114,6 +117,7 @@ module ActiveMerchant #:nodoc:
114
117
  add_metadata(post, options)
115
118
  add_months(post, options)
116
119
  add_deferred(post, options)
120
+ add_three_d_secure(post, payment_method, options)
117
121
 
118
122
  commit(action, post)
119
123
  end
@@ -133,9 +137,9 @@ module ActiveMerchant #:nodoc:
133
137
  end
134
138
 
135
139
  def add_amount_defaults(sum, money, options)
136
- sum[:subtotalIva] = amount(money).to_f
140
+ sum[:subtotalIva] = 0
137
141
  sum[:iva] = 0
138
- sum[:subtotalIva0] = 0
142
+ sum[:subtotalIva0] = amount(money).to_f
139
143
 
140
144
  sum[:ice] = 0 if sum[:currency] != 'COP'
141
145
  end
@@ -183,7 +187,8 @@ module ActiveMerchant #:nodoc:
183
187
  end
184
188
 
185
189
  def add_full_response(post, options)
186
- post[:fullResponse] = options[:full_response].to_s.casecmp('true').zero? if options[:full_response]
190
+ # this is the only currently accepted value for this field, previously it was 'true'
191
+ post[:fullResponse] = 'v2' unless options[:full_response] == 'false' || options[:full_response].blank?
187
192
  end
188
193
 
189
194
  def add_metadata(post, options)
@@ -204,6 +209,59 @@ module ActiveMerchant #:nodoc:
204
209
  }
205
210
  end
206
211
 
212
+ def add_product_details(post, options)
213
+ return unless options[:product_details]
214
+
215
+ product_items_array = []
216
+ options[:product_details].each do |item|
217
+ product_items_obj = {}
218
+
219
+ product_items_obj[:id] = item[:id] if item[:id]
220
+ product_items_obj[:title] = item[:title] if item[:title]
221
+ product_items_obj[:price] = item[:price].to_i if item[:price]
222
+ product_items_obj[:sku] = item[:sku] if item[:sku]
223
+ product_items_obj[:quantity] = item[:quantity].to_i if item[:quantity]
224
+
225
+ product_items_array << product_items_obj
226
+ end
227
+
228
+ product_items = {
229
+ product: product_items_array
230
+ }
231
+
232
+ post[:productDetails] = product_items
233
+ end
234
+
235
+ def add_three_d_secure(post, payment_method, options)
236
+ three_d_secure = options[:three_d_secure]
237
+ return unless three_d_secure.present?
238
+
239
+ post[:threeDomainSecure] = {
240
+ eci: three_d_secure[:eci],
241
+ specificationVersion: three_d_secure[:version]
242
+ }
243
+
244
+ if payment_method.brand == 'master'
245
+ post[:threeDomainSecure][:acceptRisk] = three_d_secure[:eci] == '00'
246
+ post[:threeDomainSecure][:ucaf] = three_d_secure[:cavv]
247
+ post[:threeDomainSecure][:directoryServerTransactionID] = three_d_secure[:ds_transaction_id]
248
+ case three_d_secure[:eci]
249
+ when '07'
250
+ post[:threeDomainSecure][:collectionIndicator] = '0'
251
+ when '06'
252
+ post[:threeDomainSecure][:collectionIndicator] = '1'
253
+ else
254
+ post[:threeDomainSecure][:collectionIndicator] = '2'
255
+ end
256
+ elsif payment_method.brand == 'visa'
257
+ post[:threeDomainSecure][:acceptRisk] = three_d_secure[:eci] == '07'
258
+ post[:threeDomainSecure][:cavv] = three_d_secure[:cavv]
259
+ post[:threeDomainSecure][:xid] = three_d_secure[:xid] if three_d_secure[:xid].present?
260
+ else
261
+ raise ArgumentError.new 'Kushki supports 3ds2 authentication for only Visa and Mastercard brands.'
262
+ end
263
+ end
264
+
207
265
  ENDPOINT = {
208
266
  'tokenize' => 'tokens',
209
267
  'charge' => 'charges',
@@ -213,10 +271,10 @@ module ActiveMerchant #:nodoc:
213
271
  'capture' => 'capture'
214
272
  }
215
273
 
216
- def commit(action, params)
274
+ def commit(action, params, options = {})
217
275
  response =
218
276
  begin
219
- parse(ssl_invoke(action, params))
277
+ parse(ssl_invoke(action, params, options))
220
278
  rescue ResponseError => e
221
279
  parse(e.response.body)
222
280
  end
@@ -233,9 +291,11 @@ module ActiveMerchant #:nodoc:
233
291
  )
234
292
  end
235
293
 
236
- def ssl_invoke(action, params)
294
+ def ssl_invoke(action, params, options)
237
295
  if %w[void refund].include?(action)
238
- ssl_request(:delete, url(action, params), nil, headers(action))
296
+ # removes ticketNumber from request for partial refunds because gateway will reject if included in request body
297
+ data = options[:partial_refund] == true ? post_data(params.except(:ticketNumber)) : nil
298
+ ssl_request(:delete, url(action, params), data, headers(action))
239
299
  else
240
300
  ssl_post(url(action, params), post_data(params), headers(action))
241
301
  end
@@ -263,11 +263,15 @@ module ActiveMerchant #:nodoc:
263
263
  def commit(money, creditcard, options = {})
264
264
  response = parse(ssl_post(test? ? self.test_url : self.live_url, post_data(money, creditcard, options)))
265
265
 
266
- Response.new(successful?(response), response[:message], response,
266
+ Response.new(
267
+ successful?(response),
268
+ response[:message],
269
+ response,
267
270
  test: test?,
268
271
  authorization: response[:ordernum],
269
272
  avs_result: { code: response[:avs].to_s[2, 1] },
270
- cvv_result: response[:avs].to_s[3, 1])
273
+ cvv_result: response[:avs].to_s[3, 1]
274
+ )
271
275
  end
272
276
 
273
277
  def successful?(response)
@@ -111,14 +111,15 @@ module ActiveMerchant #:nodoc:
111
111
  doc.lineItemData do
112
112
  level_3_data[:line_items].each do |line_item|
113
113
  doc.itemSequenceNumber(line_item[:item_sequence_number]) if line_item[:item_sequence_number]
114
- doc.commodityCode(line_item[:commodity_code]) if line_item[:commodity_code]
115
114
  doc.itemDescription(line_item[:item_description]) if line_item[:item_description]
116
115
  doc.productCode(line_item[:product_code]) if line_item[:product_code]
117
116
  doc.quantity(line_item[:quantity]) if line_item[:quantity]
118
117
  doc.unitOfMeasure(line_item[:unit_of_measure]) if line_item[:unit_of_measure]
119
118
  doc.taxAmount(line_item[:tax_amount]) if line_item[:tax_amount]
120
- doc.itemDiscountAmount(line_item[:discount_per_line_item]) unless line_item[:discount_per_line_item] < 0
121
- doc.unitCost(line_item[:unit_cost]) unless line_item[:unit_cost] < 0
119
+ doc.lineItemTotal(line_item[:line_item_total]) if line_item[:line_item_total]
120
+ doc.itemDiscountAmount(line_item[:discount_per_line_item].to_i) unless line_item[:discount_per_line_item].to_i < 0
121
+ doc.commodityCode(line_item[:commodity_code]) if line_item[:commodity_code]
122
+ doc.unitCost(line_item[:unit_cost].to_i) unless line_item[:unit_cost].to_i < 0
122
123
  doc.detailTax do
123
124
  doc.taxIncludedInTotal(line_item[:tax_included_in_total]) if line_item[:tax_included_in_total]
124
125
  doc.taxAmount(line_item[:tax_amount]) if line_item[:tax_amount]
@@ -310,7 +311,15 @@ module ActiveMerchant #:nodoc:
310
311
  def add_auth_purchase_params(doc, money, payment_method, options)
311
312
  doc.orderId(truncate(options[:order_id], 24))
312
313
  doc.amount(money)
313
- add_order_source(doc, payment_method, options)
314
+
315
+ if options.dig(:stored_credential, :initial_transaction) == false
316
+ # orderSource needs to be added at the top of doc and
317
+ # processingType near the end
318
+ source_for_subsequent_stored_credential_txns(doc, options)
319
+ else
320
+ add_order_source(doc, payment_method, options)
321
+ end
322
+
314
323
  add_billing_address(doc, payment_method, options)
315
324
  add_shipping_address(doc, payment_method, options)
316
325
  add_payment_method(doc, payment_method, options)
@@ -382,8 +391,9 @@ module ActiveMerchant #:nodoc:
382
391
  doc.track(payment_method.track_data)
383
392
  end
384
393
  elsif check?(payment_method)
394
+ account_type = payment_method.account_type || payment_method.account_holder_type
385
395
  doc.echeck do
386
- doc.accType(payment_method.account_type.capitalize)
396
+ doc.accType(account_type&.capitalize)
387
397
  doc.accNum(payment_method.account_number)
388
398
  doc.routingNum(payment_method.routing_number)
389
399
  doc.checkNum(payment_method.number) if payment_method.number
@@ -409,16 +419,17 @@ module ActiveMerchant #:nodoc:
409
419
  end
410
420
 
411
421
  def add_stored_credential_params(doc, options = {})
412
- return unless options[:stored_credential]
422
+ return unless stored_credential = options[:stored_credential]
413
423
 
414
- if options[:stored_credential][:initial_transaction]
415
- add_stored_credential_params_initial(doc, options)
424
+ if stored_credential[:initial_transaction]
425
+ add_stored_credential_for_initial_txn(doc, options)
416
426
  else
417
- add_stored_credential_params_used(doc, options)
427
+ doc.processingType("#{stored_credential[:initiator]}InitiatedCOF") if stored_credential[:reason_type] == 'unscheduled'
428
+ doc.originalNetworkTransactionId(stored_credential[:network_transaction_id]) if stored_credential[:initiator] == 'merchant'
418
429
  end
419
430
  end
420
431
 
421
- def add_stored_credential_params_initial(doc, options)
432
+ def add_stored_credential_for_initial_txn(doc, options)
422
433
  case options[:stored_credential][:reason_type]
423
434
  when 'unscheduled'
424
435
  doc.processingType('initialCOF')
@@ -429,15 +440,15 @@ module ActiveMerchant #:nodoc:
429
440
  end
430
441
  end
431
442
 
432
- def add_stored_credential_params_used(doc, options)
433
- if options[:stored_credential][:reason_type] == 'unscheduled'
434
- if options[:stored_credential][:initiator] == 'merchant'
435
- doc.processingType('merchantInitiatedCOF')
436
- else
437
- doc.processingType('cardholderInitiatedCOF')
438
- end
443
+ def source_for_subsequent_stored_credential_txns(doc, options)
444
+ case options[:stored_credential][:reason_type]
445
+ when 'unscheduled'
446
+ doc.orderSource('ecommerce')
447
+ when 'installment'
448
+ doc.orderSource('installment')
449
+ when 'recurring'
450
+ doc.orderSource('recurring')
439
451
  end
440
- doc.originalNetworkTransactionId(options[:stored_credential][:network_transaction_id])
441
452
  end
442
453
 
443
454
  def add_billing_address(doc, payment_method, options)
@@ -479,8 +490,7 @@ module ActiveMerchant #:nodoc:
479
490
  end
480
491
 
481
492
  def add_order_source(doc, payment_method, options)
482
- order_source = order_source(options)
483
- if order_source
493
+ if order_source = options[:order_source]
484
494
  doc.orderSource(order_source)
485
495
  elsif payment_method.is_a?(NetworkTokenizationCreditCard) && payment_method.source == :apple_pay
486
496
  doc.orderSource('applepay')
@@ -493,31 +503,6 @@ module ActiveMerchant #:nodoc:
493
503
  end
494
504
  end
495
505
 
496
- def order_source(options = {})
497
- return options[:order_source] unless options[:stored_credential]
498
-
499
- order_source = nil
500
-
501
- case options[:stored_credential][:reason_type]
502
- when 'unscheduled'
503
- if options[:stored_credential][:initiator] == 'merchant'
504
- # For merchant-initiated, we should always set order source to
505
- # 'ecommerce'
506
- order_source = 'ecommerce'
507
- else
508
- # For cardholder-initiated, we rely on #add_order_source's
509
- # default logic to set orderSource appropriately
510
- order_source = options[:order_source]
511
- end
512
- when 'installment'
513
- order_source = 'installment'
514
- when 'recurring'
515
- order_source = 'recurring'
516
- end
517
-
518
- order_source
519
- end
520
-
521
506
  def add_pos(doc, payment_method)
522
507
  return unless payment_method.respond_to?(:track_data) && payment_method.track_data.present?
523
508
 
@@ -576,7 +561,7 @@ module ActiveMerchant #:nodoc:
576
561
  end
577
562
 
578
563
  def success_from(kind, parsed)
579
- return %w(000 001 010).any?(parsed[:response]) unless kind == :registerToken
564
+ return %w(000 001 010 141 142).any?(parsed[:response]) unless kind == :registerToken
580
565
 
581
566
  %w(000 801 802).include?(parsed[:response])
582
567
  end
@@ -618,11 +603,9 @@ module ActiveMerchant #:nodoc:
618
603
  }
619
604
  end
620
605
 
621
- def build_xml_request
606
+ def build_xml_request(&block)
622
607
  builder = Nokogiri::XML::Builder.new
623
- builder.__send__('litleOnlineRequest', root_attributes) do |doc|
624
- yield(doc)
625
- end
608
+ builder.__send__('litleOnlineRequest', root_attributes, &block)
626
609
  builder.doc.root.to_xml
627
610
  end
628
611
 
@@ -10,7 +10,7 @@ module ActiveMerchant
10
10
  if options[:pay_mode]
11
11
  post = new_post
12
12
  add_invoice(post, amount, options)
13
- add_reference(post, *new_authorization)
13
+ add_reference(post, *new_authorization(options))
14
14
  add_payment_method(post, payment_method)
15
15
  add_customer_data(post, payment_method, options)
16
16
  add_3dsecure_id(post, options)
@@ -27,7 +27,7 @@ module ActiveMerchant
27
27
  def authorize(amount, payment_method, options = {})
28
28
  post = new_post
29
29
  add_invoice(post, amount, options)
30
- add_reference(post, *new_authorization)
30
+ add_reference(post, *new_authorization(options))
31
31
  add_payment_method(post, payment_method)
32
32
  add_customer_data(post, payment_method, options)
33
33
  add_3dsecure_id(post, options)
@@ -264,9 +264,9 @@ module ActiveMerchant
264
264
  authorization.split('|')
265
265
  end
266
266
 
267
- def new_authorization
267
+ def new_authorization(options)
268
268
  # Must be unique within a merchant id.
269
- orderid = SecureRandom.uuid
269
+ orderid = options[:order_id] || SecureRandom.uuid
270
270
 
271
271
  # Must be unique within an order id.
272
272
  transactionid = '1'
@@ -79,8 +79,8 @@ module ActiveMerchant #:nodoc:
79
79
 
80
80
  private
81
81
 
82
- def commit(action)
83
- request = build_xml_request(action) { |doc| yield(doc) }
82
+ def commit(action, &block)
83
+ request = build_xml_request(action, &block)
84
84
  response = parse(ssl_post(url, request, 'Content-Type' => 'text/xml'))
85
85
 
86
86
  Response.new(
@@ -180,7 +180,7 @@ module ActiveMerchant #:nodoc:
180
180
 
181
181
  def commit(action, money, parameters)
182
182
  url = test? ? self.test_url : self.live_url
183
- parameters[:transaction_amount] = amount(money) if money unless action == 'V'
183
+ parameters[:transaction_amount] = amount(money) if !(action == 'V') && money
184
184
 
185
185
  response =
186
186
  begin
@@ -189,11 +189,15 @@ module ActiveMerchant #:nodoc:
189
189
  { 'error_code' => '404', 'auth_response_text' => e.to_s }
190
190
  end
191
191
 
192
- Response.new(success_from(response), message_from(response), response,
192
+ Response.new(
193
+ success_from(response),
194
+ message_from(response),
195
+ response,
193
196
  authorization: authorization_from(response),
194
197
  test: test?,
195
198
  cvv_result: response['cvv2_result'],
196
- avs_result: { code: response['avs_result'] })
199
+ avs_result: { code: response['avs_result'] }
200
+ )
197
201
  end
198
202
 
199
203
  def authorization_from(response)
@@ -220,8 +224,7 @@ module ActiveMerchant #:nodoc:
220
224
  post[:profile_key] = @options[:password]
221
225
  post[:transaction_type] = action if action
222
226
 
223
- request = post.merge(parameters).map { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join('&')
224
- request
227
+ post.merge(parameters).map { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join('&')
225
228
  end
226
229
  end
227
230
  end
@@ -290,19 +290,26 @@ module ActiveMerchant #:nodoc:
290
290
 
291
291
  def commit(action, request, v4 = false)
292
292
  begin
293
- data = ssl_post(url(v4), request,
293
+ data = ssl_post(
294
+ url(v4),
295
+ request,
294
296
  'Content-Type' => 'text/xml; charset=utf-8',
295
- 'SOAPAction' => soap_action(action, v4))
297
+ 'SOAPAction' => soap_action(action, v4)
298
+ )
296
299
  response = parse(action, data)
297
300
  rescue ActiveMerchant::ResponseError => e
298
301
  response = parse_error(e.response)
299
302
  end
300
303
 
301
- Response.new(response[:success], response[:message], response,
304
+ Response.new(
305
+ response[:success],
306
+ response[:message],
307
+ response,
302
308
  test: test?,
303
309
  authorization: authorization_from(response),
304
310
  avs_result: { code: response['AVSResponse'] },
305
- cvv_result: response['CVResponse'])
311
+ cvv_result: response['CVResponse']
312
+ )
306
313
  end
307
314
 
308
315
  def authorization_from(response)
@@ -261,19 +261,26 @@ module ActiveMerchant #:nodoc:
261
261
 
262
262
  def commit(action, request)
263
263
  begin
264
- data = ssl_post(url, request,
264
+ data = ssl_post(
265
+ url,
266
+ request,
265
267
  'Content-Type' => 'text/xml; charset=utf-8',
266
- 'SOAPAction' => soap_action(action))
268
+ 'SOAPAction' => soap_action(action)
269
+ )
267
270
  response = parse(action, data)
268
271
  rescue ActiveMerchant::ResponseError => e
269
272
  response = parse_error(e.response, action)
270
273
  end
271
274
 
272
- Response.new(response[:success], response[:message], response,
275
+ Response.new(
276
+ response[:success],
277
+ response[:message],
278
+ response,
273
279
  test: test?,
274
280
  authorization: authorization_from(response),
275
281
  avs_result: { code: response['AvsResponse'] },
276
- cvv_result: response['CvResponse'])
282
+ cvv_result: response['CvResponse']
283
+ )
277
284
  end
278
285
 
279
286
  def authorization_from(response)
@@ -32,6 +32,8 @@ module ActiveMerchant #:nodoc:
32
32
  add_payment_method(post, payment_method)
33
33
  add_recurring_flag(post, options)
34
34
  add_soft_descriptors(post, options)
35
+ add_three_ds(post, options)
36
+ post['storeID'] = options[:store_id] if options[:store_id]
35
37
  commit('processAuth', post)
36
38
  end
37
39
 
@@ -43,6 +45,8 @@ module ActiveMerchant #:nodoc:
43
45
  add_payment_method(post, payment_method)
44
46
  add_recurring_flag(post, options)
45
47
  add_soft_descriptors(post, options)
48
+ add_three_ds(post, options)
49
+ post['storeID'] = options[:store_id] if options[:store_id]
46
50
  commit('processCard', post)
47
51
  end
48
52
 
@@ -111,9 +115,9 @@ module ActiveMerchant #:nodoc:
111
115
  post['customerCity'] = address[:city]
112
116
  post['customerAddress'] = address[:address1]
113
117
  post['customerPostCode'] = address[:zip]
114
- post['customerIP'] = address[:ip]
115
- post['customerPhone'] = address[:phone]
116
- post['customerEmail'] = address[:email]
118
+ post['customerIP'] = address[:ip] || options[:ip]
119
+ post['customerPhone'] = address[:phone] || address[:phone_number]
120
+ post['customerEmail'] = address[:email] || options[:email]
117
121
  end
118
122
 
119
123
  def add_order_id(post, options)
@@ -184,6 +188,18 @@ module ActiveMerchant #:nodoc:
184
188
  )
185
189
  end
186
190
 
191
+ def add_three_ds(post, options)
192
+ return unless three_d_secure = options[:three_d_secure]
193
+
194
+ post.merge!({
195
+ threeDSEci: three_d_secure[:eci],
196
+ threeDSXid: three_d_secure[:xid] || three_d_secure[:ds_transaction_id],
197
+ threeDSCavv: three_d_secure[:cavv],
198
+ threeDSStatus: three_d_secure[:authentication_response_status],
199
+ threeDSV2Version: three_d_secure[:version]
200
+ }.compact)
201
+ end
202
+
187
203
  def parse(body)
188
204
  xml = REXML::Document.new(body)
189
205
 
@@ -302,12 +302,16 @@ module ActiveMerchant #:nodoc:
302
302
  success = SUCCESS_CODES.include?(response[:cmd_status])
303
303
  message = success ? 'Success' : message_from(response)
304
304
 
305
- Response.new(success, message, response,
305
+ Response.new(
306
+ success,
307
+ message,
308
+ response,
306
309
  test: test?,
307
310
  authorization: authorization_from(response),
308
311
  avs_result: { code: response[:avs_result] },
309
312
  cvv_result: response[:cvv_result],
310
- error_code: success ? nil : STANDARD_ERROR_CODE_MAPPING[response[:dsix_return_code]])
313
+ error_code: success ? nil : STANDARD_ERROR_CODE_MAPPING[response[:dsix_return_code]]
314
+ )
311
315
  end
312
316
 
313
317
  def message_from(response)
@@ -175,12 +175,16 @@ module ActiveMerchant #:nodoc:
175
175
  # (TESTMODE) Successful Sale
176
176
  test_mode = test? || message =~ /TESTMODE/
177
177
 
178
- Response.new(success?(response), message, response,
178
+ Response.new(
179
+ success?(response),
180
+ message,
181
+ response,
179
182
  test: test_mode,
180
183
  authorization: response[:transaction_id],
181
184
  fraud_review: fraud_review?(response),
182
185
  avs_result: { code: response[:avs_result_code] },
183
- cvv_result: response[:card_code])
186
+ cvv_result: response[:card_code]
187
+ )
184
188
  end
185
189
 
186
190
  def success?(response)
@@ -194,7 +198,7 @@ module ActiveMerchant #:nodoc:
194
198
  def parse(body)
195
199
  fields = split(body)
196
200
 
197
- results = {
201
+ {
198
202
  response_code: fields[RESPONSE_CODE].to_i,
199
203
  response_reason_code: fields[RESPONSE_REASON_CODE],
200
204
  response_reason_text: fields[RESPONSE_REASON_TEXT],
@@ -202,7 +206,6 @@ module ActiveMerchant #:nodoc:
202
206
  transaction_id: fields[TRANSACTION_ID],
203
207
  card_code: fields[CARD_CODE_RESPONSE_CODE]
204
208
  }
205
- results
206
209
  end
207
210
 
208
211
  def post_data(action, parameters = {})
@@ -218,8 +221,7 @@ module ActiveMerchant #:nodoc:
218
221
  post[:encap_char] = '$'
219
222
  post[:solution_ID] = application_id if application_id
220
223
 
221
- request = post.merge(parameters).collect { |key, value| "x_#{key}=#{CGI.escape(value.to_s)}" }.join('&')
222
- request
224
+ post.merge(parameters).collect { |key, value| "x_#{key}=#{CGI.escape(value.to_s)}" }.join('&')
223
225
  end
224
226
 
225
227
  def add_invoice(post, options)
@@ -71,6 +71,7 @@ module ActiveMerchant
71
71
 
72
72
  class CreditCardType
73
73
  attr_accessor :am_code, :migs_code, :migs_long_code, :name
74
+
74
75
  def initialize(am_code, migs_code, migs_long_code, name)
75
76
  @am_code = am_code
76
77
  @migs_code = migs_code
@@ -281,12 +281,16 @@ module ActiveMerchant #:nodoc:
281
281
  cvv_result_code = response[:CSCResultCode]
282
282
  cvv_result_code = 'P' if cvv_result_code == 'Unsupported'
283
283
 
284
- Response.new(success?(response), response[:Message], response,
284
+ Response.new(
285
+ success?(response),
286
+ response[:Message],
287
+ response,
285
288
  test: test?,
286
289
  authorization: response[:TransactionNo],
287
290
  fraud_review: fraud_review?(response),
288
291
  avs_result: { code: avs_response_code },
289
- cvv_result: cvv_result_code)
292
+ cvv_result: cvv_result_code
293
+ )
290
294
  end
291
295
 
292
296
  def success?(response)