activemerchant 1.100.0 → 1.133.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (267) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +1057 -0
  3. data/README.md +11 -9
  4. data/lib/active_merchant/billing/avs_result.rb +9 -9
  5. data/lib/active_merchant/billing/base.rb +0 -13
  6. data/lib/active_merchant/billing/check.rb +49 -17
  7. data/lib/active_merchant/billing/compatibility.rb +5 -4
  8. data/lib/active_merchant/billing/credit_card.rb +55 -8
  9. data/lib/active_merchant/billing/credit_card_formatting.rb +1 -0
  10. data/lib/active_merchant/billing/credit_card_methods.rb +209 -36
  11. data/lib/active_merchant/billing/cvv_result.rb +0 -1
  12. data/lib/active_merchant/billing/gateway.rb +38 -36
  13. data/lib/active_merchant/billing/gateways/adyen.rb +399 -78
  14. data/lib/active_merchant/billing/gateways/airwallex.rb +370 -0
  15. data/lib/active_merchant/billing/gateways/alelo.rb +256 -0
  16. data/lib/active_merchant/billing/gateways/allied_wallet.rb +14 -14
  17. data/lib/active_merchant/billing/gateways/authorize_net.rb +200 -130
  18. data/lib/active_merchant/billing/gateways/authorize_net_arb.rb +27 -20
  19. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +48 -51
  20. data/lib/active_merchant/billing/gateways/axcessms.rb +13 -15
  21. data/lib/active_merchant/billing/gateways/balanced.rb +43 -36
  22. data/lib/active_merchant/billing/gateways/bambora_apac.rb +16 -20
  23. data/lib/active_merchant/billing/gateways/bank_frick.rb +13 -13
  24. data/lib/active_merchant/billing/gateways/banwire.rb +5 -5
  25. data/lib/active_merchant/billing/gateways/barclaycard_smartpay.rb +43 -30
  26. data/lib/active_merchant/billing/gateways/barclays_epdq_extra_plus.rb +1 -1
  27. data/lib/active_merchant/billing/gateways/be2bill.rb +5 -5
  28. data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +37 -36
  29. data/lib/active_merchant/billing/gateways/beanstream.rb +21 -3
  30. data/lib/active_merchant/billing/gateways/beanstream_interac.rb +1 -1
  31. data/lib/active_merchant/billing/gateways/blue_pay.rb +53 -28
  32. data/lib/active_merchant/billing/gateways/blue_snap.rb +176 -54
  33. data/lib/active_merchant/billing/gateways/bogus.rb +24 -20
  34. data/lib/active_merchant/billing/gateways/borgun.rb +92 -38
  35. data/lib/active_merchant/billing/gateways/bpoint.rb +15 -15
  36. data/lib/active_merchant/billing/gateways/braintree/braintree_common.rb +8 -2
  37. data/lib/active_merchant/billing/gateways/braintree/token_nonce.rb +113 -0
  38. data/lib/active_merchant/billing/gateways/braintree.rb +1 -1
  39. data/lib/active_merchant/billing/gateways/braintree_blue.rb +387 -175
  40. data/lib/active_merchant/billing/gateways/bridge_pay.rb +13 -13
  41. data/lib/active_merchant/billing/gateways/cams.rb +10 -10
  42. data/lib/active_merchant/billing/gateways/card_connect.rb +33 -14
  43. data/lib/active_merchant/billing/gateways/card_save.rb +3 -4
  44. data/lib/active_merchant/billing/gateways/card_stream.rb +67 -40
  45. data/lib/active_merchant/billing/gateways/cardknox.rb +13 -13
  46. data/lib/active_merchant/billing/gateways/cardprocess.rb +4 -2
  47. data/lib/active_merchant/billing/gateways/cashnet.rb +28 -12
  48. data/lib/active_merchant/billing/gateways/cc5.rb +9 -9
  49. data/lib/active_merchant/billing/gateways/cecabank.rb +38 -38
  50. data/lib/active_merchant/billing/gateways/cenpos.rb +29 -28
  51. data/lib/active_merchant/billing/gateways/checkout.rb +7 -9
  52. data/lib/active_merchant/billing/gateways/checkout_v2.rb +316 -68
  53. data/lib/active_merchant/billing/gateways/citrus_pay.rb +1 -2
  54. data/lib/active_merchant/billing/gateways/clearhaus.rb +32 -33
  55. data/lib/active_merchant/billing/gateways/commerce_hub.rb +370 -0
  56. data/lib/active_merchant/billing/gateways/commercegate.rb +4 -4
  57. data/lib/active_merchant/billing/gateways/conekta.rb +8 -6
  58. data/lib/active_merchant/billing/gateways/creditcall.rb +18 -17
  59. data/lib/active_merchant/billing/gateways/credorax.rb +152 -63
  60. data/lib/active_merchant/billing/gateways/ct_payment.rb +15 -14
  61. data/lib/active_merchant/billing/gateways/culqi.rb +30 -28
  62. data/lib/active_merchant/billing/gateways/cyber_source/cyber_source_common.rb +36 -0
  63. data/lib/active_merchant/billing/gateways/cyber_source.rb +496 -187
  64. data/lib/active_merchant/billing/gateways/cyber_source_rest.rb +454 -0
  65. data/lib/active_merchant/billing/gateways/d_local.rb +148 -31
  66. data/lib/active_merchant/billing/gateways/data_cash.rb +34 -37
  67. data/lib/active_merchant/billing/gateways/decidir.rb +134 -21
  68. data/lib/active_merchant/billing/gateways/decidir_plus.rb +344 -0
  69. data/lib/active_merchant/billing/gateways/dibs.rb +10 -10
  70. data/lib/active_merchant/billing/gateways/digitzs.rb +11 -8
  71. data/lib/active_merchant/billing/gateways/ebanx.rb +90 -40
  72. data/lib/active_merchant/billing/gateways/efsnet.rb +36 -36
  73. data/lib/active_merchant/billing/gateways/elavon.rb +349 -194
  74. data/lib/active_merchant/billing/gateways/element.rb +71 -21
  75. data/lib/active_merchant/billing/gateways/epay.rb +43 -43
  76. data/lib/active_merchant/billing/gateways/evo_ca.rb +12 -13
  77. data/lib/active_merchant/billing/gateways/eway.rb +9 -9
  78. data/lib/active_merchant/billing/gateways/eway_managed.rb +55 -56
  79. data/lib/active_merchant/billing/gateways/eway_rapid.rb +37 -22
  80. data/lib/active_merchant/billing/gateways/exact.rb +19 -20
  81. data/lib/active_merchant/billing/gateways/ezic.rb +9 -9
  82. data/lib/active_merchant/billing/gateways/fat_zebra.rb +24 -19
  83. data/lib/active_merchant/billing/gateways/federated_canada.rb +6 -7
  84. data/lib/active_merchant/billing/gateways/finansbank.rb +3 -3
  85. data/lib/active_merchant/billing/gateways/first_giving.rb +5 -4
  86. data/lib/active_merchant/billing/gateways/first_pay.rb +7 -7
  87. data/lib/active_merchant/billing/gateways/firstdata_e4.rb +39 -38
  88. data/lib/active_merchant/billing/gateways/firstdata_e4_v27.rb +51 -31
  89. data/lib/active_merchant/billing/gateways/flo2cash.rb +24 -24
  90. data/lib/active_merchant/billing/gateways/flo2cash_simple.rb +1 -1
  91. data/lib/active_merchant/billing/gateways/forte.rb +38 -22
  92. data/lib/active_merchant/billing/gateways/garanti.rb +12 -15
  93. data/lib/active_merchant/billing/gateways/global_collect.rb +333 -89
  94. data/lib/active_merchant/billing/gateways/global_transport.rb +8 -9
  95. data/lib/active_merchant/billing/gateways/hdfc.rb +22 -23
  96. data/lib/active_merchant/billing/gateways/hps.rb +171 -50
  97. data/lib/active_merchant/billing/gateways/iats_payments.rb +47 -25
  98. data/lib/active_merchant/billing/gateways/in_context_paypal_express.rb +1 -1
  99. data/lib/active_merchant/billing/gateways/inspire.rb +22 -27
  100. data/lib/active_merchant/billing/gateways/instapay.rb +5 -8
  101. data/lib/active_merchant/billing/gateways/ipg.rb +420 -0
  102. data/lib/active_merchant/billing/gateways/ipp.rb +9 -9
  103. data/lib/active_merchant/billing/gateways/iridium.rb +30 -31
  104. data/lib/active_merchant/billing/gateways/itransact.rb +11 -10
  105. data/lib/active_merchant/billing/gateways/iveri.rb +62 -23
  106. data/lib/active_merchant/billing/gateways/ixopay.rb +320 -0
  107. data/lib/active_merchant/billing/gateways/jetpay.rb +10 -17
  108. data/lib/active_merchant/billing/gateways/jetpay_v2.rb +13 -18
  109. data/lib/active_merchant/billing/gateways/komoju.rb +1 -1
  110. data/lib/active_merchant/billing/gateways/kushki.rb +100 -22
  111. data/lib/active_merchant/billing/gateways/latitude19.rb +20 -19
  112. data/lib/active_merchant/billing/gateways/linkpoint.rb +71 -72
  113. data/lib/active_merchant/billing/gateways/litle.rb +181 -45
  114. data/lib/active_merchant/billing/gateways/mastercard.rb +16 -22
  115. data/lib/active_merchant/billing/gateways/maxipago.rb +2 -2
  116. data/lib/active_merchant/billing/gateways/mercado_pago.rb +89 -18
  117. data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +58 -24
  118. data/lib/active_merchant/billing/gateways/merchant_one.rb +7 -10
  119. data/lib/active_merchant/billing/gateways/merchant_partners.rb +19 -19
  120. data/lib/active_merchant/billing/gateways/merchant_ware.rb +18 -22
  121. data/lib/active_merchant/billing/gateways/merchant_ware_version_four.rb +15 -17
  122. data/lib/active_merchant/billing/gateways/merchant_warrior.rb +46 -8
  123. data/lib/active_merchant/billing/gateways/mercury.rb +19 -23
  124. data/lib/active_merchant/billing/gateways/metrics_global.rb +24 -33
  125. data/lib/active_merchant/billing/gateways/micropayment.rb +11 -12
  126. data/lib/active_merchant/billing/gateways/migs/migs_codes.rb +7 -7
  127. data/lib/active_merchant/billing/gateways/migs.rb +18 -21
  128. data/lib/active_merchant/billing/gateways/mit.rb +260 -0
  129. data/lib/active_merchant/billing/gateways/modern_payments_cim.rb +10 -12
  130. data/lib/active_merchant/billing/gateways/moka.rb +290 -0
  131. data/lib/active_merchant/billing/gateways/monei.rb +236 -150
  132. data/lib/active_merchant/billing/gateways/moneris.rb +122 -53
  133. data/lib/active_merchant/billing/gateways/money_movers.rb +6 -7
  134. data/lib/active_merchant/billing/gateways/mundipagg.rb +69 -23
  135. data/lib/active_merchant/billing/gateways/nab_transact.rb +18 -20
  136. data/lib/active_merchant/billing/gateways/ncr_secure_pay.rb +10 -12
  137. data/lib/active_merchant/billing/gateways/net_registry.rb +8 -9
  138. data/lib/active_merchant/billing/gateways/netaxept.rb +12 -12
  139. data/lib/active_merchant/billing/gateways/netbanx.rb +128 -46
  140. data/lib/active_merchant/billing/gateways/netbilling.rb +18 -21
  141. data/lib/active_merchant/billing/gateways/netpay.rb +5 -4
  142. data/lib/active_merchant/billing/gateways/network_merchants.rb +7 -10
  143. data/lib/active_merchant/billing/gateways/nmi.rb +69 -27
  144. data/lib/active_merchant/billing/gateways/ogone.rb +62 -31
  145. data/lib/active_merchant/billing/gateways/omise.rb +15 -16
  146. data/lib/active_merchant/billing/gateways/openpay.rb +33 -15
  147. data/lib/active_merchant/billing/gateways/opp.rb +39 -33
  148. data/lib/active_merchant/billing/gateways/optimal_payment.rb +43 -42
  149. data/lib/active_merchant/billing/gateways/orbital/orbital_soft_descriptors.rb +3 -5
  150. data/lib/active_merchant/billing/gateways/orbital.rb +623 -362
  151. data/lib/active_merchant/billing/gateways/pac_net_raven.rb +20 -20
  152. data/lib/active_merchant/billing/gateways/pagarme.rb +16 -23
  153. data/lib/active_merchant/billing/gateways/pago_facil.rb +4 -6
  154. data/lib/active_merchant/billing/gateways/pay_arc.rb +392 -0
  155. data/lib/active_merchant/billing/gateways/pay_conex.rb +17 -17
  156. data/lib/active_merchant/billing/gateways/pay_gate_xml.rb +30 -33
  157. data/lib/active_merchant/billing/gateways/pay_hub.rb +10 -10
  158. data/lib/active_merchant/billing/gateways/pay_junction.rb +31 -31
  159. data/lib/active_merchant/billing/gateways/pay_junction_v2.rb +36 -18
  160. data/lib/active_merchant/billing/gateways/pay_secure.rb +10 -11
  161. data/lib/active_merchant/billing/gateways/pay_trace.rb +450 -0
  162. data/lib/active_merchant/billing/gateways/paybox_direct.rb +64 -40
  163. data/lib/active_merchant/billing/gateways/payeezy.rb +130 -27
  164. data/lib/active_merchant/billing/gateways/payex.rb +24 -25
  165. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +17 -17
  166. data/lib/active_merchant/billing/gateways/payflow/payflow_express_response.rb +1 -1
  167. data/lib/active_merchant/billing/gateways/payflow.rb +103 -25
  168. data/lib/active_merchant/billing/gateways/payflow_express.rb +4 -4
  169. data/lib/active_merchant/billing/gateways/payflow_uk.rb +1 -1
  170. data/lib/active_merchant/billing/gateways/payment_express.rb +22 -18
  171. data/lib/active_merchant/billing/gateways/paymentez.rb +89 -24
  172. data/lib/active_merchant/billing/gateways/paymill.rb +14 -16
  173. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +2 -1
  174. data/lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb +4 -0
  175. data/lib/active_merchant/billing/gateways/paypal.rb +13 -5
  176. data/lib/active_merchant/billing/gateways/paypal_ca.rb +1 -1
  177. data/lib/active_merchant/billing/gateways/paypal_digital_goods.rb +1 -1
  178. data/lib/active_merchant/billing/gateways/paypal_express.rb +4 -1
  179. data/lib/active_merchant/billing/gateways/paypal_express_common.rb +1 -1
  180. data/lib/active_merchant/billing/gateways/paysafe.rb +420 -0
  181. data/lib/active_merchant/billing/gateways/payscout.rb +8 -9
  182. data/lib/active_merchant/billing/gateways/paystation.rb +6 -9
  183. data/lib/active_merchant/billing/gateways/payu_in.rb +20 -19
  184. data/lib/active_merchant/billing/gateways/payu_latam.rb +70 -37
  185. data/lib/active_merchant/billing/gateways/payway.rb +22 -22
  186. data/lib/active_merchant/billing/gateways/payway_dot_com.rb +253 -0
  187. data/lib/active_merchant/billing/gateways/pin.rb +60 -21
  188. data/lib/active_merchant/billing/gateways/plexo.rb +308 -0
  189. data/lib/active_merchant/billing/gateways/plugnpay.rb +20 -21
  190. data/lib/active_merchant/billing/gateways/priority.rb +392 -0
  191. data/lib/active_merchant/billing/gateways/pro_pay.rb +13 -14
  192. data/lib/active_merchant/billing/gateways/psigate.rb +29 -29
  193. data/lib/active_merchant/billing/gateways/psl_card.rb +7 -8
  194. data/lib/active_merchant/billing/gateways/qbms.rb +25 -26
  195. data/lib/active_merchant/billing/gateways/quantum.rb +9 -11
  196. data/lib/active_merchant/billing/gateways/quickbooks.rb +126 -39
  197. data/lib/active_merchant/billing/gateways/quickpay/quickpay_common.rb +98 -98
  198. data/lib/active_merchant/billing/gateways/quickpay/quickpay_v10.rb +19 -23
  199. data/lib/active_merchant/billing/gateways/quickpay/quickpay_v4to7.rb +3 -3
  200. data/lib/active_merchant/billing/gateways/quickpay.rb +0 -1
  201. data/lib/active_merchant/billing/gateways/qvalent.rb +36 -20
  202. data/lib/active_merchant/billing/gateways/rapyd.rb +319 -0
  203. data/lib/active_merchant/billing/gateways/reach.rb +277 -0
  204. data/lib/active_merchant/billing/gateways/realex.rb +42 -16
  205. data/lib/active_merchant/billing/gateways/redsys.rb +191 -86
  206. data/lib/active_merchant/billing/gateways/s5.rb +10 -9
  207. data/lib/active_merchant/billing/gateways/safe_charge.rb +70 -33
  208. data/lib/active_merchant/billing/gateways/sage.rb +19 -21
  209. data/lib/active_merchant/billing/gateways/sage_pay.rb +57 -57
  210. data/lib/active_merchant/billing/gateways/sallie_mae.rb +3 -4
  211. data/lib/active_merchant/billing/gateways/secure_net.rb +19 -26
  212. data/lib/active_merchant/billing/gateways/secure_pay.rb +24 -33
  213. data/lib/active_merchant/billing/gateways/secure_pay_au.rb +18 -20
  214. data/lib/active_merchant/billing/gateways/secure_pay_tech.rb +4 -5
  215. data/lib/active_merchant/billing/gateways/securion_pay.rb +48 -7
  216. data/lib/active_merchant/billing/gateways/shift4.rb +345 -0
  217. data/lib/active_merchant/billing/gateways/simetrik.rb +368 -0
  218. data/lib/active_merchant/billing/gateways/skip_jack.rb +19 -19
  219. data/lib/active_merchant/billing/gateways/smart_ps.rb +26 -32
  220. data/lib/active_merchant/billing/gateways/so_easy_pay.rb +24 -25
  221. data/lib/active_merchant/billing/gateways/spreedly_core.rb +27 -21
  222. data/lib/active_merchant/billing/gateways/stripe.rb +126 -53
  223. data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +441 -113
  224. data/lib/active_merchant/billing/gateways/swipe_checkout.rb +7 -8
  225. data/lib/active_merchant/billing/gateways/telr.rb +17 -18
  226. data/lib/active_merchant/billing/gateways/tns.rb +3 -7
  227. data/lib/active_merchant/billing/gateways/trans_first.rb +10 -9
  228. data/lib/active_merchant/billing/gateways/trans_first_transaction_express.rb +28 -24
  229. data/lib/active_merchant/billing/gateways/transact_pro.rb +13 -15
  230. data/lib/active_merchant/billing/gateways/transax.rb +1 -2
  231. data/lib/active_merchant/billing/gateways/trexle.rb +5 -2
  232. data/lib/active_merchant/billing/gateways/trust_commerce.rb +57 -47
  233. data/lib/active_merchant/billing/gateways/usa_epay.rb +1 -2
  234. data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +176 -184
  235. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +60 -48
  236. data/lib/active_merchant/billing/gateways/vanco.rb +17 -8
  237. data/lib/active_merchant/billing/gateways/verifi.rb +13 -14
  238. data/lib/active_merchant/billing/gateways/viaklix.rb +9 -14
  239. data/lib/active_merchant/billing/gateways/visanet_peru.rb +26 -21
  240. data/lib/active_merchant/billing/gateways/vpos.rb +223 -0
  241. data/lib/active_merchant/billing/gateways/webpay.rb +4 -4
  242. data/lib/active_merchant/billing/gateways/wepay.rb +14 -16
  243. data/lib/active_merchant/billing/gateways/wirecard.rb +14 -16
  244. data/lib/active_merchant/billing/gateways/wompi.rb +197 -0
  245. data/lib/active_merchant/billing/gateways/world_net.rb +36 -35
  246. data/lib/active_merchant/billing/gateways/worldpay.rb +556 -190
  247. data/lib/active_merchant/billing/gateways/worldpay_online_payments.rb +47 -54
  248. data/lib/active_merchant/billing/gateways/worldpay_us.rb +16 -16
  249. data/lib/active_merchant/billing/network_tokenization_credit_card.rb +2 -2
  250. data/lib/active_merchant/billing/response.rb +25 -6
  251. data/lib/active_merchant/billing/three_d_secure_eci_mapper.rb +27 -0
  252. data/lib/active_merchant/billing.rb +1 -0
  253. data/lib/active_merchant/connection.rb +14 -15
  254. data/lib/active_merchant/country.rb +3 -1
  255. data/lib/active_merchant/errors.rb +4 -1
  256. data/lib/active_merchant/net_http_ssl_connection.rb +1 -0
  257. data/lib/active_merchant/network_connection_retries.rb +15 -17
  258. data/lib/active_merchant/post_data.rb +3 -2
  259. data/lib/active_merchant/posts_data.rb +2 -2
  260. data/lib/active_merchant/version.rb +1 -1
  261. data/lib/active_merchant.rb +2 -2
  262. data/lib/certs/cacert.pem +1587 -2361
  263. data/lib/support/gateway_support.rb +1 -1
  264. data/lib/support/ssl_verify.rb +3 -7
  265. data/lib/support/ssl_version.rb +2 -3
  266. metadata +86 -34
  267. data/lib/active_merchant/billing/gateways/moneris_us.rb +0 -352
@@ -8,25 +8,24 @@ module ActiveMerchant #:nodoc:
8
8
 
9
9
  self.default_currency = 'GBP'
10
10
  self.money_format = :cents
11
- self.supported_countries = %w(HK GB AU AD AR BE BR CA CH CN CO CR CY CZ DE DK ES FI FR GI GR HU IE IN IT JP LI LU MC MT MY MX NL NO NZ PA PE PL PT SE SG SI SM TR UM VA)
12
- self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :maestro, :elo, :naranja, :cabal]
13
- self.currencies_without_fractions = %w(HUF IDR ISK JPY KRW)
14
- self.currencies_with_three_decimal_places = %w(BHD KWD OMR RSD TND)
11
+ self.supported_countries = %w(AD AE AG AI AL AM AO AR AS AT AU AW AX AZ BA BB BD BE BF BG BH BI BJ BM BN BO BR BS BT BW
12
+ BY BZ CA CC CF CH CK CL CM CN CO CR CV CX CY CZ DE DJ DK DO DZ EC EE EG EH ES ET FI FJ FK
13
+ FM FO FR GA GB GD GE GF GG GH GI GL GM GN GP GQ GR GT GU GW GY HK HM HN HR HT HU ID IE IL
14
+ IM IN IO IS IT JE JM JO JP KE KG KH KI KM KN KR KW KY KZ LA LC LI LK LS LT LU LV MA MC MD
15
+ ME MG MH MK ML 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
16
+ OM PA PE PF PH PK PL PN PR PT PW PY QA RE RO RS RU RW SA SB SC SE SG SI SK SL SM SN ST SV
17
+ SZ TC TD TF TG TH TJ TK TM TO TR TT TV TW TZ UA UG US UY UZ VA VC VE VI VN VU WF WS YE YT
18
+ ZA ZM)
19
+ self.supported_cardtypes = %i[visa master american_express discover jcb maestro elo naranja cabal unionpay]
20
+ self.currencies_without_fractions = %w(HUF IDR JPY KRW BEF XOF XAF XPF GRD GNF ITL LUF MGA MGF PYG PTE RWF ESP TRL VND KMF)
21
+ self.currencies_with_three_decimal_places = %w(BHD KWD OMR TND LYD JOD IQD)
15
22
  self.homepage_url = 'http://www.worldpay.com/'
16
23
  self.display_name = 'Worldpay Global'
17
24
 
18
- CARD_CODES = {
19
- 'visa' => 'VISA-SSL',
20
- 'master' => 'ECMC-SSL',
21
- 'discover' => 'DISCOVER-SSL',
22
- 'american_express' => 'AMEX-SSL',
23
- 'jcb' => 'JCB-SSL',
24
- 'maestro' => 'MAESTRO-SSL',
25
- 'diners_club' => 'DINERS-SSL',
26
- 'elo' => 'ELO-SSL',
27
- 'naranja' => 'NARANJA-SSL',
28
- 'cabal' => 'CABAL-SSL',
29
- 'unknown' => 'CARD-SSL'
25
+ NETWORK_TOKEN_TYPE = {
26
+ apple_pay: 'APPLEPAY',
27
+ google_pay: 'GOOGLEPAY',
28
+ network_token: 'NETWORKTOKEN'
30
29
  }
31
30
 
32
31
  AVS_CODE_MAP = {
@@ -57,23 +56,23 @@ module ActiveMerchant #:nodoc:
57
56
  def purchase(money, payment_method, options = {})
58
57
  MultiResponse.run do |r|
59
58
  r.process { authorize(money, payment_method, options) }
60
- r.process { capture(money, r.authorization, options.merge(:authorization_validated => true)) }
59
+ r.process { capture(money, r.authorization, options.merge(authorization_validated: true)) } unless options[:skip_capture]
61
60
  end
62
61
  end
63
62
 
64
63
  def authorize(money, payment_method, options = {})
65
64
  requires!(options, :order_id)
66
- payment_details = payment_details_from(payment_method)
65
+ payment_details = payment_details(payment_method)
67
66
  authorize_request(money, payment_method, payment_details.merge(options))
68
67
  end
69
68
 
70
69
  def capture(money, authorization, options = {})
71
70
  authorization = order_id_from_authorization(authorization.to_s)
72
71
  MultiResponse.run do |r|
73
- r.process { inquire_request(authorization, options, 'AUTHORISED') } unless options[:authorization_validated]
72
+ r.process { inquire_request(authorization, options, 'AUTHORISED', 'CAPTURED') } unless options[:authorization_validated]
74
73
  if r.params
75
74
  authorization_currency = r.params['amount_currency_code']
76
- options = options.merge(:currency => authorization_currency) if authorization_currency.present?
75
+ options = options.merge(currency: authorization_currency) if authorization_currency.present?
77
76
  end
78
77
  r.process { capture_request(money, authorization, options) }
79
78
  end
@@ -89,15 +88,19 @@ module ActiveMerchant #:nodoc:
89
88
 
90
89
  def refund(money, authorization, options = {})
91
90
  authorization = order_id_from_authorization(authorization.to_s)
91
+ success_criteria = %w(CAPTURED SETTLED SETTLED_BY_MERCHANT SENT_FOR_REFUND)
92
+ success_criteria.push('AUTHORIZED') if options[:cancel_or_refund]
92
93
  response = MultiResponse.run do |r|
93
- r.process { inquire_request(authorization, options, 'CAPTURED', 'SETTLED', 'SETTLED_BY_MERCHANT') } unless options[:authorization_validated]
94
+ r.process { inquire_request(authorization, options, *success_criteria) } unless options[:authorization_validated]
94
95
  r.process { refund_request(money, authorization, options) }
95
96
  end
96
97
 
97
- return response if response.success?
98
- return response unless options[:force_full_refund_if_unsettled]
99
-
100
- void(authorization, options) if response.params['last_event'] == 'AUTHORISED'
98
+ if !response.success? && options[:force_full_refund_if_unsettled] &&
99
+ response.params['last_event'] == 'AUTHORISED'
100
+ void(authorization, options)
101
+ else
102
+ response
103
+ end
101
104
  end
102
105
 
103
106
  # Credits only function on a Merchant ID/login/profile flagged for Payouts
@@ -105,41 +108,57 @@ module ActiveMerchant #:nodoc:
105
108
  # and other transactions should be performed on a normal eCom-flagged
106
109
  # merchant ID.
107
110
  def credit(money, payment_method, options = {})
108
- payment_details = payment_details_from(payment_method)
109
- credit_request(money, payment_method, payment_details.merge(:credit => true, **options))
111
+ payment_details = payment_details(payment_method)
112
+ if options[:fast_fund_credit]
113
+ fast_fund_credit_request(money, payment_method, payment_details.merge(credit: true, **options))
114
+ else
115
+ credit_request(money, payment_method, payment_details.merge(credit: true, **options))
116
+ end
110
117
  end
111
118
 
112
- def verify(payment_method, options={})
119
+ def verify(payment_method, options = {})
120
+ amount = (eligible_for_0_auth?(payment_method, options) ? 0 : 100)
113
121
  MultiResponse.run(:use_first_response) do |r|
114
- r.process { authorize(100, payment_method, options) }
115
- r.process(:ignore_result) { void(r.authorization, options.merge(:authorization_validated => true)) }
122
+ r.process { authorize(amount, payment_method, options) }
123
+ r.process(:ignore_result) { void(r.authorization, options.merge(authorization_validated: true)) }
116
124
  end
117
125
  end
118
126
 
119
- def store(credit_card, options={})
127
+ def store(credit_card, options = {})
120
128
  requires!(options, :customer)
121
129
  store_request(credit_card, options)
122
130
  end
123
131
 
132
+ def inquire(authorization, options = {})
133
+ order_id = order_id_from_authorization(authorization.to_s) || options[:order_id]
134
+ commit('direct_inquiry', build_order_inquiry_request(order_id, options), :ok, options)
135
+ end
136
+
124
137
  def supports_scrubbing
125
138
  true
126
139
  end
127
140
 
141
+ def supports_network_tokenization?
142
+ true
143
+ end
144
+
128
145
  def scrub(transcript)
129
146
  transcript.
130
147
  gsub(%r((Authorization: Basic )\w+), '\1[FILTERED]').
131
148
  gsub(%r((<cardNumber>)\d+(</cardNumber>)), '\1[FILTERED]\2').
132
- gsub(%r((<cvc>)[^<]+(</cvc>)), '\1[FILTERED]\2')
149
+ gsub(%r((<cvc>)[^<]+(</cvc>)), '\1[FILTERED]\2').
150
+ gsub(%r((<tokenNumber>)\d+(</tokenNumber>)), '\1[FILTERED]\2').
151
+ gsub(%r((<cryptogram>)[^<]+(</cryptogram>)), '\1[FILTERED]\2')
133
152
  end
134
153
 
135
154
  private
136
155
 
137
156
  def authorize_request(money, payment_method, options)
138
- commit('authorize', build_authorization_request(money, payment_method, options), 'AUTHORISED', options)
157
+ commit('authorize', build_authorization_request(money, payment_method, options), 'AUTHORISED', 'CAPTURED', options)
139
158
  end
140
159
 
141
160
  def capture_request(money, authorization, options)
142
- commit('capture', build_capture_request(money, authorization, options), :ok, options)
161
+ commit('capture', build_capture_request(money, authorization, options), 'CAPTURED', :ok, options)
143
162
  end
144
163
 
145
164
  def cancel_request(authorization, options)
@@ -151,22 +170,26 @@ module ActiveMerchant #:nodoc:
151
170
  end
152
171
 
153
172
  def refund_request(money, authorization, options)
154
- commit('refund', build_refund_request(money, authorization, options), :ok, options)
173
+ commit('refund', build_refund_request(money, authorization, options), :ok, 'SENT_FOR_REFUND', options)
155
174
  end
156
175
 
157
176
  def credit_request(money, payment_method, options)
158
177
  commit('credit', build_authorization_request(money, payment_method, options), :ok, 'SENT_FOR_REFUND', options)
159
178
  end
160
179
 
180
+ def fast_fund_credit_request(money, payment_method, options)
181
+ commit('fast_credit', build_fast_fund_credit_request(money, payment_method, options), :ok, 'PUSH_APPROVED', options)
182
+ end
183
+
161
184
  def store_request(credit_card, options)
162
185
  commit('store', build_store_request(credit_card, options), options)
163
186
  end
164
187
 
165
188
  def build_request
166
- xml = Builder::XmlMarkup.new :indent => 2
167
- xml.instruct! :xml, :encoding => 'UTF-8'
189
+ xml = Builder::XmlMarkup.new indent: 2
190
+ xml.instruct! :xml, encoding: 'UTF-8'
168
191
  xml.declare! :DOCTYPE, :paymentService, :PUBLIC, '-//WorldPay//DTD WorldPay PaymentService v1//EN', 'http://dtd.worldpay.com/paymentService_v1.dtd'
169
- xml.tag! 'paymentService', 'version' => '1.4', 'merchantCode' => @options[:login] do
192
+ xml.paymentService 'version' => '1.4', 'merchantCode' => @options[:login] do
170
193
  yield xml
171
194
  end
172
195
  xml.target!
@@ -174,8 +197,8 @@ module ActiveMerchant #:nodoc:
174
197
 
175
198
  def build_order_modify_request(authorization)
176
199
  build_request do |xml|
177
- xml.tag! 'modify' do
178
- xml.tag! 'orderModification', 'orderCode' => authorization do
200
+ xml.modify do
201
+ xml.orderModification 'orderCode' => authorization do
179
202
  yield xml
180
203
  end
181
204
  end
@@ -184,31 +207,27 @@ module ActiveMerchant #:nodoc:
184
207
 
185
208
  def build_order_inquiry_request(authorization, options)
186
209
  build_request do |xml|
187
- xml.tag! 'inquiry' do
188
- xml.tag! 'orderInquiry', 'orderCode' => authorization
210
+ xml.inquiry do
211
+ xml.orderInquiry 'orderCode' => authorization
189
212
  end
190
213
  end
191
214
  end
192
215
 
193
216
  def build_authorization_request(money, payment_method, options)
194
217
  build_request do |xml|
195
- xml.tag! 'submit' do
196
- xml.tag! 'order', order_tag_attributes(options) do
218
+ xml.submit do
219
+ xml.order order_tag_attributes(options) do
197
220
  xml.description(options[:description].blank? ? 'Purchase' : options[:description])
198
221
  add_amount(xml, money, options)
199
- if options[:order_content]
200
- xml.tag! 'orderContent' do
201
- xml.cdata! options[:order_content]
202
- end
203
- end
222
+ add_order_content(xml, options)
204
223
  add_payment_method(xml, money, payment_method, options)
205
224
  add_shopper(xml, options)
206
- if options[:hcg_additional_data]
207
- add_hcg_additional_data(xml, options)
208
- end
209
- if options[:instalments]
210
- add_instalments_data(xml, options)
211
- end
225
+ add_statement_narrative(xml, options)
226
+ add_risk_data(xml, options[:risk_data]) if options[:risk_data]
227
+ add_sub_merchant_data(xml, options[:sub_merchant_data]) if options[:sub_merchant_data]
228
+ add_hcg_additional_data(xml, options) if options[:hcg_additional_data]
229
+ add_instalments_data(xml, options) if options[:instalments]
230
+ add_additional_data(xml, money, options) if options[:level_2_data] || options[:level_3_data]
212
231
  add_moto_flag(xml, options) if options.dig(:metadata, :manual_entry)
213
232
  add_additional_3ds_data(xml, options) if options[:execute_threed] && options[:three_ds_version] && options[:three_ds_version] =~ /^2/
214
233
  add_3ds_exemption(xml, options) if options[:exemption_type]
@@ -217,56 +236,321 @@ module ActiveMerchant #:nodoc:
217
236
  end
218
237
  end
219
238
 
239
+ def add_additional_data(xml, amount, options)
240
+ level_two_data = options[:level_2_data] || {}
241
+ level_three_data = options[:level_3_data] || {}
242
+ level_two_and_three_data = level_two_data.merge(level_three_data).symbolize_keys
243
+
244
+ xml.branchSpecificExtension do
245
+ xml.purchase do
246
+ add_level_two_and_three_data(xml, amount, level_two_and_three_data)
247
+ end
248
+ end
249
+ end
250
+
251
+ def add_level_two_and_three_data(xml, amount, data)
252
+ xml.invoiceReferenceNumber data[:invoice_reference_number] if data.include?(:invoice_reference_number)
253
+ xml.customerReference data[:customer_reference] if data.include?(:customer_reference)
254
+ xml.cardAcceptorTaxId data[:card_acceptor_tax_id] if data.include?(:card_acceptor_tax_id)
255
+
256
+ {
257
+ sales_tax: 'salesTax',
258
+ discount_amount: 'discountAmount',
259
+ shipping_amount: 'shippingAmount',
260
+ duty_amount: 'dutyAmount'
261
+ }.each do |key, tag|
262
+ next unless data.include?(key)
263
+
264
+ xml.tag! tag do
265
+ data_amount = data[key].symbolize_keys
266
+ add_amount(xml, data_amount[:amount].to_i, data_amount)
267
+ end
268
+ end
269
+
270
+ xml.discountName data[:discount_name] if data.include?(:discount_name)
271
+ xml.discountCode data[:discount_code] if data.include?(:discount_code)
272
+
273
+ add_date_element(xml, 'shippingDate', data[:shipping_date]) if data.include?(:shipping_date)
274
+
275
+ if data.include?(:shipping_courier)
276
+ xml.shippingCourier(
277
+ data[:shipping_courier][:priority],
278
+ data[:shipping_courier][:tracking_number],
279
+ data[:shipping_courier][:name]
280
+ )
281
+ end
282
+
283
+ add_optional_data_level_two_and_three(xml, data)
284
+
285
+ if data.include?(:item) && data[:item].kind_of?(Array)
286
+ data[:item].each { |item| add_items_into_level_three_data(xml, item.symbolize_keys) }
287
+ elsif data.include?(:item)
288
+ add_items_into_level_three_data(xml, data[:item].symbolize_keys)
289
+ end
290
+ end
291
+
292
+ def add_items_into_level_three_data(xml, item)
293
+ xml.item do
294
+ xml.description item[:description] if item[:description]
295
+ xml.productCode item[:product_code] if item[:product_code]
296
+ xml.commodityCode item[:commodity_code] if item[:commodity_code]
297
+ xml.quantity item[:quantity] if item[:quantity]
298
+
299
+ {
300
+ unit_cost: 'unitCost',
301
+ item_total: 'itemTotal',
302
+ item_total_with_tax: 'itemTotalWithTax',
303
+ item_discount_amount: 'itemDiscountAmount',
304
+ tax_amount: 'taxAmount'
305
+ }.each do |key, tag|
306
+ next unless item.include?(key)
307
+
308
+ xml.tag! tag do
309
+ data_amount = item[key].symbolize_keys
310
+ add_amount(xml, data_amount[:amount].to_i, data_amount)
311
+ end
312
+ end
313
+ end
314
+ end
315
+
316
+ def add_optional_data_level_two_and_three(xml, data)
317
+ xml.shipFromPostalCode data[:ship_from_postal_code] if data.include?(:ship_from_postal_code)
318
+ xml.destinationPostalCode data[:destination_postal_code] if data.include?(:destination_postal_code)
319
+ xml.destinationCountryCode data[:destination_country_code] if data.include?(:destination_country_code)
320
+ add_date_element(xml, 'orderDate', data[:order_date].symbolize_keys) if data.include?(:order_date)
321
+ xml.taxExempt data[:tax_exempt] if data.include?(:tax_exempt)
322
+ end
323
+
220
324
  def order_tag_attributes(options)
221
- { 'orderCode' => options[:order_id], 'installationId' => options[:inst_id] || @options[:inst_id] }.reject { |_, v| !v }
325
+ { 'orderCode' => clean_order_id(options[:order_id]), 'installationId' => options[:inst_id] || @options[:inst_id] }.reject { |_, v| !v.present? }
326
+ end
327
+
328
+ def clean_order_id(order_id)
329
+ order_id.to_s.gsub(/(\s|\||<|>|'|")/, '')[0..64]
330
+ end
331
+
332
+ def add_order_content(xml, options)
333
+ return unless options[:order_content]
334
+
335
+ xml.orderContent do
336
+ xml.cdata! options[:order_content]
337
+ end
222
338
  end
223
339
 
224
340
  def build_capture_request(money, authorization, options)
225
341
  build_order_modify_request(authorization) do |xml|
226
- xml.tag! 'capture' do
342
+ xml.capture do
227
343
  time = Time.now
228
- xml.tag! 'date', 'dayOfMonth' => time.day, 'month' => time.month, 'year'=> time.year
344
+ xml.date 'dayOfMonth' => time.day, 'month' => time.month, 'year' => time.year
229
345
  add_amount(xml, money, options)
230
346
  end
231
347
  end
232
348
  end
233
349
 
234
350
  def build_void_request(authorization, options)
235
- build_order_modify_request(authorization) do |xml|
236
- xml.tag! 'cancel'
351
+ if options[:cancel_or_refund]
352
+ build_order_modify_request(authorization, &:cancelOrRefund)
353
+ else
354
+ build_order_modify_request(authorization, &:cancel)
237
355
  end
238
356
  end
239
357
 
240
358
  def build_refund_request(money, authorization, options)
241
359
  build_order_modify_request(authorization) do |xml|
242
- xml.tag! 'refund' do
243
- add_amount(xml, money, options.merge(:debit_credit_indicator => 'credit'))
360
+ if options[:cancel_or_refund]
361
+ # Worldpay docs claim amount must be passed. This causes an error.
362
+ xml.cancelOrRefund # { add_amount(xml, money, options.merge(debit_credit_indicator: 'credit')) }
363
+ else
364
+ xml.refund do
365
+ add_amount(xml, money, options.merge(debit_credit_indicator: 'credit'))
366
+ end
244
367
  end
245
368
  end
246
369
  end
247
370
 
248
371
  def build_store_request(credit_card, options)
249
372
  build_request do |xml|
250
- xml.tag! 'submit' do
251
- xml.tag! 'paymentTokenCreate' do
373
+ xml.submit do
374
+ xml.paymentTokenCreate do
252
375
  add_authenticated_shopper_id(xml, options)
253
- xml.tag! 'createToken'
254
- xml.tag! 'paymentInstrument' do
255
- xml.tag! 'cardDetails' do
376
+ xml.createToken
377
+ xml.paymentInstrument do
378
+ xml.cardDetails do
256
379
  add_card(xml, credit_card, options)
257
380
  end
258
381
  end
382
+ add_transaction_identifier(xml, options) if network_transaction_id(options)
383
+ end
384
+ end
385
+ end
386
+ end
387
+
388
+ def network_transaction_id(options)
389
+ options[:stored_credential_transaction_id] || options.dig(:stored_credential, :network_transaction_id)
390
+ end
391
+
392
+ def add_transaction_identifier(xml, options)
393
+ xml.storedCredentials 'usage' => 'FIRST' do
394
+ xml.schemeTransactionIdentifier network_transaction_id(options)
395
+ end
396
+ end
397
+
398
+ def build_fast_fund_credit_request(money, payment_method, options)
399
+ build_request do |xml|
400
+ xml.submit do
401
+ xml.order order_tag_attributes(options) do
402
+ xml.description(options[:description].blank? ? 'Fast Fund Credit' : options[:description])
403
+ add_amount(xml, money, options)
404
+ add_order_content(xml, options)
405
+ add_payment_details_for_ff_credit(xml, payment_method, options)
406
+ add_shopper_id(xml, options)
259
407
  end
260
408
  end
261
409
  end
262
410
  end
263
411
 
412
+ def add_payment_details_for_ff_credit(xml, payment_method, options)
413
+ xml.paymentDetails do
414
+ xml.tag! 'FF_DISBURSE-SSL' do
415
+ if payment_method.is_a?(CreditCard)
416
+ add_card_for_ff_credit(xml, payment_method, options)
417
+ else
418
+ add_token_for_ff_credit(xml, payment_method, options)
419
+ end
420
+ end
421
+ end
422
+ end
423
+
424
+ def add_card_for_ff_credit(xml, payment_method, options)
425
+ xml.recipient do
426
+ xml.paymentInstrument do
427
+ xml.cardDetails do
428
+ add_card(xml, payment_method, options)
429
+ end
430
+ end
431
+ end
432
+ end
433
+
434
+ def add_token_for_ff_credit(xml, payment_method, options)
435
+ return unless payment_method.is_a?(String)
436
+
437
+ token_details = token_details_from_authorization(payment_method)
438
+
439
+ xml.tag! 'recipient', 'tokenScope' => token_details[:token_scope] do
440
+ xml.paymentTokenID token_details[:token_id]
441
+ add_authenticated_shopper_id(xml, token_details)
442
+ end
443
+ end
444
+
264
445
  def add_additional_3ds_data(xml, options)
265
- xml.tag! 'additional3DSData', 'dfReferenceId' => options[:session_id]
446
+ additional_data = { 'dfReferenceId' => options[:session_id] }
447
+ additional_data['challengeWindowSize'] = options[:browser_size] if options[:browser_size]
448
+
449
+ xml.additional3DSData additional_data
266
450
  end
267
451
 
268
452
  def add_3ds_exemption(xml, options)
269
- xml.tag! 'exemption', 'type' => options[:exemption_type], 'placement' => options[:exemption_placement] || 'AUTHORISATION'
453
+ xml.exemption 'type' => options[:exemption_type], 'placement' => options[:exemption_placement] || 'AUTHORISATION'
454
+ end
455
+
456
+ def add_risk_data(xml, risk_data)
457
+ xml.riskData do
458
+ add_authentication_risk_data(xml, risk_data[:authentication_risk_data])
459
+ add_shopper_account_risk_data(xml, risk_data[:shopper_account_risk_data])
460
+ add_transaction_risk_data(xml, risk_data[:transaction_risk_data])
461
+ end
462
+ end
463
+
464
+ def add_authentication_risk_data(xml, authentication_risk_data)
465
+ return unless authentication_risk_data
466
+
467
+ timestamp = authentication_risk_data.fetch(:authentication_date, {})
468
+
469
+ xml.authenticationRiskData('authenticationMethod' => authentication_risk_data[:authentication_method]) do
470
+ xml.authenticationTimestamp do
471
+ xml.date(
472
+ 'dayOfMonth' => timestamp[:day_of_month],
473
+ 'month' => timestamp[:month],
474
+ 'year' => timestamp[:year],
475
+ 'hour' => timestamp[:hour],
476
+ 'minute' => timestamp[:minute],
477
+ 'second' => timestamp[:second]
478
+ )
479
+ end
480
+ end
481
+ end
482
+
483
+ def add_sub_merchant_data(xml, options)
484
+ xml.subMerchantData do
485
+ xml.pfId options[:pf_id] if options[:pf_id]
486
+ xml.subName options[:sub_name] if options[:sub_name]
487
+ xml.subId options[:sub_id] if options[:sub_id]
488
+ xml.subStreet options[:sub_street] if options[:sub_street]
489
+ xml.subCity options[:sub_city] if options[:sub_city]
490
+ xml.subState options[:sub_state] if options[:sub_state]
491
+ xml.subCountryCode options[:sub_country_code] if options[:sub_country_code]
492
+ xml.subPostalCode options[:sub_postal_code] if options[:sub_postal_code]
493
+ xml.subTaxId options[:sub_tax_id] if options[:sub_tax_id]
494
+ end
495
+ end
496
+
497
+ def add_shopper_account_risk_data(xml, shopper_account_risk_data)
498
+ return unless shopper_account_risk_data
499
+
500
+ data = {
501
+ 'transactionsAttemptedLastDay' => shopper_account_risk_data[:transactions_attempted_last_day],
502
+ 'transactionsAttemptedLastYear' => shopper_account_risk_data[:transactions_attempted_last_year],
503
+ 'purchasesCompletedLastSixMonths' => shopper_account_risk_data[:purchases_completed_last_six_months],
504
+ 'addCardAttemptsLastDay' => shopper_account_risk_data[:add_card_attempts_last_day],
505
+ 'previousSuspiciousActivity' => shopper_account_risk_data[:previous_suspicious_activity],
506
+ 'shippingNameMatchesAccountName' => shopper_account_risk_data[:shipping_name_matches_account_name],
507
+ 'shopperAccountAgeIndicator' => shopper_account_risk_data[:shopper_account_age_indicator],
508
+ 'shopperAccountChangeIndicator' => shopper_account_risk_data[:shopper_account_change_indicator],
509
+ 'shopperAccountPasswordChangeIndicator' => shopper_account_risk_data[:shopper_account_password_change_indicator],
510
+ 'shopperAccountShippingAddressUsageIndicator' => shopper_account_risk_data[:shopper_account_shipping_address_usage_indicator],
511
+ 'shopperAccountPaymentAccountIndicator' => shopper_account_risk_data[:shopper_account_payment_account_indicator]
512
+ }.reject { |_k, v| v.nil? }
513
+
514
+ xml.shopperAccountRiskData(data) do
515
+ add_date_element(xml, 'shopperAccountCreationDate', shopper_account_risk_data[:shopper_account_creation_date])
516
+ add_date_element(xml, 'shopperAccountModificationDate', shopper_account_risk_data[:shopper_account_modification_date])
517
+ add_date_element(xml, 'shopperAccountPasswordChangeDate', shopper_account_risk_data[:shopper_account_password_change_date])
518
+ add_date_element(xml, 'shopperAccountShippingAddressFirstUseDate', shopper_account_risk_data[:shopper_account_shipping_address_first_use_date])
519
+ add_date_element(xml, 'shopperAccountPaymentAccountFirstUseDate', shopper_account_risk_data[:shopper_account_payment_account_first_use_date])
520
+ end
521
+ end
522
+
523
+ def add_transaction_risk_data(xml, transaction_risk_data)
524
+ return unless transaction_risk_data
525
+
526
+ data = {
527
+ 'shippingMethod' => transaction_risk_data[:shipping_method],
528
+ 'deliveryTimeframe' => transaction_risk_data[:delivery_timeframe],
529
+ 'deliveryEmailAddress' => transaction_risk_data[:delivery_email_address],
530
+ 'reorderingPreviousPurchases' => transaction_risk_data[:reordering_previous_purchases],
531
+ 'preOrderPurchase' => transaction_risk_data[:pre_order_purchase],
532
+ 'giftCardCount' => transaction_risk_data[:gift_card_count]
533
+ }.reject { |_k, v| v.nil? }
534
+
535
+ xml.transactionRiskData(data) do
536
+ xml.transactionRiskDataGiftCardAmount do
537
+ amount_hash = {
538
+ 'value' => transaction_risk_data.dig(:transaction_risk_data_gift_card_amount, :value),
539
+ 'currencyCode' => transaction_risk_data.dig(:transaction_risk_data_gift_card_amount, :currency),
540
+ 'exponent' => transaction_risk_data.dig(:transaction_risk_data_gift_card_amount, :exponent)
541
+ }
542
+ debit_credit_indicator = transaction_risk_data.dig(:transaction_risk_data_gift_card_amount, :debit_credit_indicator)
543
+ amount_hash['debitCreditIndicator'] = debit_credit_indicator if debit_credit_indicator
544
+ xml.amount(amount_hash)
545
+ end
546
+ add_date_element(xml, 'transactionRiskDataPreOrderDate', transaction_risk_data[:transaction_risk_data_pre_order_date])
547
+ end
548
+ end
549
+
550
+ def add_date_element(xml, name, date)
551
+ xml.tag! name do
552
+ xml.date('dayOfMonth' => date[:day_of_month], 'month' => date[:month], 'year' => date[:year])
553
+ end
270
554
  end
271
555
 
272
556
  def add_amount(xml, money, options)
@@ -278,76 +562,120 @@ module ActiveMerchant #:nodoc:
278
562
  'exponent' => currency_exponent(currency)
279
563
  }
280
564
 
281
- if options[:debit_credit_indicator]
282
- amount_hash['debitCreditIndicator'] = options[:debit_credit_indicator]
283
- end
565
+ amount_hash['debitCreditIndicator'] = options[:debit_credit_indicator] if options[:debit_credit_indicator]
284
566
 
285
- xml.tag! 'amount', amount_hash
567
+ xml.amount amount_hash
286
568
  end
287
569
 
288
570
  def add_payment_method(xml, amount, payment_method, options)
289
- if options[:payment_type] == :pay_as_order
290
- if options[:merchant_code]
291
- xml.tag! 'payAsOrder', 'orderCode' => payment_method, 'merchantCode' => options[:merchant_code] do
292
- add_amount(xml, amount, options)
293
- end
294
- else
295
- xml.tag! 'payAsOrder', 'orderCode' => payment_method do
296
- add_amount(xml, amount, options)
297
- end
571
+ case options[:payment_type]
572
+ when :pay_as_order
573
+ add_amount_for_pay_as_order(xml, amount, payment_method, options)
574
+ when :network_token
575
+ add_network_tokenization_card(xml, payment_method)
576
+ else
577
+ add_card_or_token(xml, payment_method, options)
578
+ end
579
+ end
580
+
581
+ def add_amount_for_pay_as_order(xml, amount, payment_method, options)
582
+ if options[:merchant_code]
583
+ xml.payAsOrder 'orderCode' => payment_method, 'merchantCode' => options[:merchant_code] do
584
+ add_amount(xml, amount, options)
298
585
  end
299
586
  else
300
- xml.tag! 'paymentDetails', credit_fund_transfer_attribute(options) do
301
- if options[:payment_type] == :token
302
- xml.tag! 'TOKEN-SSL', 'tokenScope' => options[:token_scope] do
303
- xml.tag! 'paymentTokenID', options[:token_id]
304
- end
305
- else
306
- xml.tag! card_code_for(payment_method) do
307
- add_card(xml, payment_method, options)
308
- end
309
- end
310
- add_stored_credential_options(xml, options)
311
- if options[:ip] && options[:session_id]
312
- xml.tag! 'session', 'shopperIPAddress' => options[:ip], 'id' => options[:session_id]
313
- else
314
- xml.tag! 'session', 'shopperIPAddress' => options[:ip] if options[:ip]
315
- xml.tag! 'session', 'id' => options[:session_id] if options[:session_id]
316
- end
587
+ xml.payAsOrder 'orderCode' => payment_method do
588
+ add_amount(xml, amount, options)
589
+ end
590
+ end
591
+ end
592
+
593
+ def add_network_tokenization_card(xml, payment_method)
594
+ token_type = NETWORK_TOKEN_TYPE.fetch(payment_method.source, 'NETWORKTOKEN')
317
595
 
318
- if three_d_secure = options[:three_d_secure]
319
- add_three_d_secure(three_d_secure, xml)
596
+ xml.paymentDetails do
597
+ xml.tag! 'EMVCO_TOKEN-SSL', 'type' => token_type do
598
+ xml.tokenNumber payment_method.number
599
+ xml.expiryDate do
600
+ xml.date(
601
+ 'month' => format(payment_method.month, :two_digits),
602
+ 'year' => format(payment_method.year, :four_digits_year)
603
+ )
320
604
  end
605
+ name = card_holder_name(payment_method, options)
606
+ eci = format(payment_method.eci, :two_digits)
607
+ xml.cardHolderName name if name.present?
608
+ xml.cryptogram payment_method.payment_cryptogram
609
+ xml.eciIndicator eci.empty? ? '07' : eci
321
610
  end
322
611
  end
323
612
  end
324
613
 
325
- def add_three_d_secure(three_d_secure, xml)
326
- xml.tag! 'info3DSecure' do
327
- xml.tag! 'threeDSVersion', three_d_secure[:version]
328
- if three_d_secure[:version] =~ /^2/
329
- xml.tag! 'dsTransactionId', three_d_secure[:ds_transaction_id]
614
+ def add_card_or_token(xml, payment_method, options)
615
+ xml.paymentDetails credit_fund_transfer_attribute(options) do
616
+ if options[:payment_type] == :token
617
+ add_token_details(xml, options)
330
618
  else
331
- xml.tag! 'xid', three_d_secure[:xid]
619
+ add_card_details(xml, payment_method, options)
332
620
  end
333
- xml.tag! 'cavv', three_d_secure[:cavv]
334
- xml.tag! 'eci', three_d_secure[:eci]
621
+ add_stored_credential_options(xml, options)
622
+ add_shopper_id(xml, options)
623
+ add_three_d_secure(xml, options)
335
624
  end
336
625
  end
337
626
 
338
- def add_card(xml, payment_method, options)
339
- xml.tag! 'cardNumber', payment_method.number
340
- xml.tag! 'expiryDate' do
341
- xml.tag! 'date', 'month' => format(payment_method.month, :two_digits), 'year' => format(payment_method.year, :four_digits)
627
+ def add_token_details(xml, options)
628
+ xml.tag! 'TOKEN-SSL', 'tokenScope' => options[:token_scope] do
629
+ xml.paymentTokenID options[:token_id]
630
+ end
631
+ end
632
+
633
+ def add_card_details(xml, payment_method, options)
634
+ xml.tag! 'CARD-SSL' do
635
+ add_card(xml, payment_method, options)
636
+ end
637
+ end
638
+
639
+ def add_shopper_id(xml, options)
640
+ if options[:ip] && options[:session_id]
641
+ xml.session 'shopperIPAddress' => options[:ip], 'id' => options[:session_id]
642
+ else
643
+ xml.session 'shopperIPAddress' => options[:ip] if options[:ip]
644
+ xml.session 'id' => options[:session_id] if options[:session_id]
342
645
  end
646
+ end
343
647
 
344
- xml.tag! 'cardHolderName', options[:execute_threed] && (options[:three_ds_version] =~ /[^2]/).nil? ? '3D' : payment_method.name
345
- xml.tag! 'cvc', payment_method.verification_value
648
+ def add_three_d_secure(xml, options)
649
+ return unless three_d_secure = options[:three_d_secure]
346
650
 
347
- add_address(xml, (options[:billing_address] || options[:address]))
651
+ xml.info3DSecure do
652
+ xml.threeDSVersion three_d_secure[:version]
653
+ if three_d_secure[:version] && three_d_secure[:ds_transaction_id]
654
+ xml.dsTransactionId three_d_secure[:ds_transaction_id]
655
+ else
656
+ xml.xid three_d_secure[:xid]
657
+ end
658
+ xml.cavv three_d_secure[:cavv]
659
+ xml.eci three_d_secure[:eci]
660
+ end
348
661
  end
349
662
 
350
- def add_stored_credential_options(xml, options={})
663
+ def add_card(xml, payment_method, options)
664
+ xml.cardNumber payment_method.number
665
+ xml.expiryDate do
666
+ xml.date(
667
+ 'month' => format(payment_method.month, :two_digits),
668
+ 'year' => format(payment_method.year, :four_digits_year)
669
+ )
670
+ end
671
+ name = card_holder_name(payment_method, options)
672
+ xml.cardHolderName name if name.present?
673
+ xml.cvc payment_method.verification_value
674
+
675
+ add_address(xml, (options[:billing_address] || options[:address]), options)
676
+ end
677
+
678
+ def add_stored_credential_options(xml, options = {})
351
679
  if options[:stored_credential]
352
680
  add_stored_credential_using_normalized_fields(xml, options)
353
681
  else
@@ -357,7 +685,7 @@ module ActiveMerchant #:nodoc:
357
685
 
358
686
  def add_stored_credential_using_normalized_fields(xml, options)
359
687
  if options[:stored_credential][:initial_transaction]
360
- xml.tag! 'storedCredentials', 'usage' => 'FIRST'
688
+ xml.storedCredentials 'usage' => 'FIRST'
361
689
  else
362
690
  reason = case options[:stored_credential][:reason_type]
363
691
  when 'installment' then 'INSTALMENT'
@@ -365,8 +693,8 @@ module ActiveMerchant #:nodoc:
365
693
  when 'unscheduled' then 'UNSCHEDULED'
366
694
  end
367
695
 
368
- xml.tag! 'storedCredentials', 'usage' => 'USED', 'merchantInitiatedReason' => reason do
369
- xml.tag! 'schemeTransactionIdentifier', options[:stored_credential][:network_transaction_id] if options[:stored_credential][:network_transaction_id]
696
+ xml.storedCredentials 'usage' => 'USED', 'merchantInitiatedReason' => reason do
697
+ xml.schemeTransactionIdentifier options[:stored_credential][:network_transaction_id] if options[:stored_credential][:network_transaction_id]
370
698
  end
371
699
  end
372
700
  end
@@ -375,69 +703,74 @@ module ActiveMerchant #:nodoc:
375
703
  return unless options[:stored_credential_usage]
376
704
 
377
705
  if options[:stored_credential_initiated_reason]
378
- xml.tag! 'storedCredentials', 'usage' => options[:stored_credential_usage], 'merchantInitiatedReason' => options[:stored_credential_initiated_reason] do
379
- xml.tag! 'schemeTransactionIdentifier', options[:stored_credential_transaction_id] if options[:stored_credential_transaction_id]
706
+ xml.storedCredentials 'usage' => options[:stored_credential_usage], 'merchantInitiatedReason' => options[:stored_credential_initiated_reason] do
707
+ xml.schemeTransactionIdentifier options[:stored_credential_transaction_id] if options[:stored_credential_transaction_id]
380
708
  end
381
709
  else
382
- xml.tag! 'storedCredentials', 'usage' => options[:stored_credential_usage]
710
+ xml.storedCredentials 'usage' => options[:stored_credential_usage]
383
711
  end
384
712
  end
385
713
 
386
714
  def add_shopper(xml, options)
387
715
  return unless options[:execute_threed] || options[:email] || options[:customer]
388
- xml.tag! 'shopper' do
389
- xml.tag! 'shopperEmailAddress', options[:email] if options[:email]
716
+
717
+ xml.shopper do
718
+ xml.shopperEmailAddress options[:email] if options[:email]
390
719
  add_authenticated_shopper_id(xml, options)
391
- xml.tag! 'browser' do
392
- xml.tag! 'acceptHeader', options[:accept_header]
393
- xml.tag! 'userAgentHeader', options[:user_agent]
720
+ xml.browser do
721
+ xml.acceptHeader options[:accept_header]
722
+ xml.userAgentHeader options[:user_agent]
394
723
  end
395
724
  end
396
725
  end
397
726
 
727
+ def add_statement_narrative(xml, options)
728
+ xml.statementNarrative truncate(options[:statement_narrative], 50) if options[:statement_narrative]
729
+ end
730
+
398
731
  def add_authenticated_shopper_id(xml, options)
399
- xml.tag!('authenticatedShopperID', options[:customer]) if options[:customer]
732
+ xml.authenticatedShopperID options[:customer] if options[:customer]
400
733
  end
401
734
 
402
- def add_address(xml, address)
735
+ def add_address(xml, address, options)
403
736
  return unless address
404
737
 
405
738
  address = address_with_defaults(address)
406
739
 
407
- xml.tag! 'cardAddress' do
408
- xml.tag! 'address' do
740
+ xml.cardAddress do
741
+ xml.address do
409
742
  if m = /^\s*([^\s]+)\s+(.+)$/.match(address[:name])
410
- xml.tag! 'firstName', m[1]
411
- xml.tag! 'lastName', m[2]
743
+ xml.firstName m[1]
744
+ xml.lastName m[2]
412
745
  end
413
- xml.tag! 'address1', address[:address1]
414
- xml.tag! 'address2', address[:address2] if address[:address2]
415
- xml.tag! 'postalCode', address[:zip]
416
- xml.tag! 'city', address[:city]
417
- xml.tag! 'state', address[:state]
418
- xml.tag! 'countryCode', address[:country]
419
- xml.tag! 'telephoneNumber', address[:phone] if address[:phone]
746
+ xml.address1 address[:address1]
747
+ xml.address2 address[:address2] if address[:address2]
748
+ xml.postalCode address[:zip]
749
+ xml.city address[:city]
750
+ xml.state address[:state] unless address[:country] != 'US' && options[:execute_threed]
751
+ xml.countryCode address[:country]
752
+ xml.telephoneNumber address[:phone] if address[:phone]
420
753
  end
421
754
  end
422
755
  end
423
756
 
424
757
  def add_hcg_additional_data(xml, options)
425
- xml.tag! 'hcgAdditionalData' do
758
+ xml.hcgAdditionalData do
426
759
  options[:hcg_additional_data].each do |k, v|
427
- xml.tag! 'param', {name: k.to_s}, v
760
+ xml.param({ name: k.to_s }, v)
428
761
  end
429
762
  end
430
763
  end
431
764
 
432
765
  def add_instalments_data(xml, options)
433
- xml.tag! 'thirdPartyData' do
434
- xml.tag! 'instalments', options[:instalments]
435
- xml.tag! 'cpf', options[:cpf] if options[:cpf]
766
+ xml.thirdPartyData do
767
+ xml.instalments options[:instalments]
768
+ xml.cpf options[:cpf] if options[:cpf]
436
769
  end
437
770
  end
438
771
 
439
772
  def add_moto_flag(xml, options)
440
- xml.tag! 'dynamicInteractionType', 'type' => 'MOTO'
773
+ xml.dynamicInteractionType 'type' => 'MOTO'
441
774
  end
442
775
 
443
776
  def address_with_defaults(address)
@@ -448,11 +781,10 @@ module ActiveMerchant #:nodoc:
448
781
 
449
782
  def default_address
450
783
  {
451
- address1: 'N/A',
452
784
  zip: '0000',
785
+ country: 'US',
453
786
  city: 'N/A',
454
- state: 'N/A',
455
- country: 'US'
787
+ address1: 'N/A'
456
788
  }
457
789
  end
458
790
 
@@ -460,12 +792,21 @@ module ActiveMerchant #:nodoc:
460
792
  xml = xml.strip.gsub(/\&/, '&amp;')
461
793
  doc = Nokogiri::XML(xml, &:strict)
462
794
  doc.remove_namespaces!
463
- resp_params = {:action => action}
795
+ resp_params = { action: action }
464
796
 
465
797
  parse_elements(doc.root, resp_params)
798
+ extract_issuer_response(doc.root, resp_params)
799
+
466
800
  resp_params
467
801
  end
468
802
 
803
+ def extract_issuer_response(doc, response)
804
+ return unless issuer_response = doc.at_xpath('//paymentService//reply//orderStatus//payment//IssuerResponseCode')
805
+
806
+ response[:issuer_response_code] = issuer_response['code']
807
+ response[:issuer_response_description] = issuer_response['description']
808
+ end
809
+
469
810
  def parse_elements(node, response)
470
811
  node_name = node.name.underscore
471
812
  node.attributes.each do |k, v|
@@ -482,42 +823,49 @@ module ActiveMerchant #:nodoc:
482
823
  end
483
824
 
484
825
  def headers(options)
826
+ idempotency_key = options[:idempotency_key]
827
+
485
828
  headers = {
486
829
  'Content-Type' => 'text/xml',
487
830
  'Authorization' => encoded_credentials
488
831
  }
489
- if options[:cookie]
490
- headers['Cookie'] = options[:cookie] if options[:cookie]
491
- end
832
+
833
+ # ensure cookie included on follow-up '3ds' and 'capture_request' calls, using the cookie saved from the preceding response
834
+ # cookie should be present in options on the 3ds and capture calls, but also still saved in the instance var in case
835
+ cookie = options[:cookie] || @cookie || nil
836
+ headers['Cookie'] = cookie if cookie
837
+
838
+ headers['Idempotency-Key'] = idempotency_key if idempotency_key
492
839
  headers
493
840
  end
494
841
 
495
842
  def commit(action, request, *success_criteria, options)
496
843
  xml = ssl_post(url, request, headers(options))
497
844
  raw = parse(action, xml)
845
+
498
846
  if options[:execute_threed]
499
- raw[:cookie] = @cookie
847
+ raw[:cookie] = @cookie if defined?(@cookie)
500
848
  raw[:session_id] = options[:session_id]
501
849
  raw[:is3DSOrder] = true
502
850
  end
503
851
  success = success_from(action, raw, success_criteria)
504
- message = message_from(success, raw, success_criteria)
852
+ message = message_from(success, raw, success_criteria, action)
505
853
 
506
854
  Response.new(
507
855
  success,
508
856
  message,
509
857
  raw,
510
- :authorization => authorization_from(action, raw, options),
511
- :error_code => error_code_from(success, raw),
512
- :test => test?,
513
- :avs_result => AVSResult.new(code: AVS_CODE_MAP[raw[:avs_result_code_description]]),
514
- :cvv_result => CVVResult.new(CVC_CODE_MAP[raw[:cvc_result_code_description]])
858
+ authorization: authorization_from(action, raw, options),
859
+ error_code: error_code_from(success, raw),
860
+ test: test?,
861
+ avs_result: AVSResult.new(code: AVS_CODE_MAP[raw[:avs_result_code_description]]),
862
+ cvv_result: CVVResult.new(CVC_CODE_MAP[raw[:cvc_result_code_description]])
515
863
  )
516
864
  rescue Nokogiri::SyntaxError
517
865
  unparsable_response(xml)
518
866
  rescue ActiveMerchant::ResponseError => e
519
867
  if e.response.code.to_s == '401'
520
- return Response.new(false, 'Invalid credentials', {}, :test => test?)
868
+ return Response.new(false, 'Invalid credentials', {}, test: test?)
521
869
  else
522
870
  raise e
523
871
  end
@@ -538,7 +886,8 @@ module ActiveMerchant #:nodoc:
538
886
  def handle_response(response)
539
887
  case response.code.to_i
540
888
  when 200...300
541
- @cookie = response['Set-Cookie']
889
+ cookie = response.header['Set-Cookie']&.match('^[^;]*')
890
+ @cookie = cookie[0] if cookie
542
891
  response.body
543
892
  else
544
893
  raise ResponseError.new(response)
@@ -549,9 +898,10 @@ module ActiveMerchant #:nodoc:
549
898
  success_criteria_success?(raw, success_criteria) || action_success?(action, raw)
550
899
  end
551
900
 
552
- def message_from(success, raw, success_criteria)
901
+ def message_from(success, raw, success_criteria, action)
553
902
  return 'SUCCESS' if success
554
- raw[:iso8583_return_code_description] || raw[:error] || required_status_message(raw, success_criteria)
903
+
904
+ raw[:iso8583_return_code_description] || raw[:error] || required_status_message(raw, success_criteria, action) || raw[:issuer_response_description]
555
905
  end
556
906
 
557
907
  # success_criteria can be:
@@ -559,28 +909,31 @@ module ActiveMerchant #:nodoc:
559
909
  # - An array of strings if one of many responses could be considered a
560
910
  # success.
561
911
  def success_criteria_success?(raw, success_criteria)
562
- success_criteria.include?(raw[:last_event]) || raw[:ok].present?
912
+ return if raw[:error]
913
+
914
+ raw[:ok].present? || (success_criteria.include?(raw[:last_event]) if raw[:last_event])
563
915
  end
564
916
 
565
917
  def action_success?(action, raw)
566
918
  case action
567
919
  when 'store'
568
920
  raw[:token].present?
921
+ when 'direct_inquiry'
922
+ raw[:last_event].present?
569
923
  else
570
924
  false
571
925
  end
572
926
  end
573
927
 
574
928
  def error_code_from(success, raw)
575
- unless success == 'SUCCESS'
576
- raw[:iso8583_return_code_code] || raw[:error_code] || nil
577
- end
929
+ raw[:iso8583_return_code_code] || raw[:error_code] || nil unless success == 'SUCCESS'
578
930
  end
579
931
 
580
- def required_status_message(raw, success_criteria)
581
- if(!success_criteria.include?(raw[:last_event]))
582
- "A transaction status of #{success_criteria.collect { |c| "'#{c}'" }.join(" or ")} is required."
583
- end
932
+ def required_status_message(raw, success_criteria, action)
933
+ return if success_criteria.include?(raw[:last_event])
934
+ return unless %w[cancel refund inquiry credit fast_credit].include?(action)
935
+
936
+ "A transaction status of #{success_criteria.collect { |c| "'#{c}'" }.join(' or ')} is required."
584
937
  end
585
938
 
586
939
  def authorization_from(action, raw, options)
@@ -600,11 +953,11 @@ module ActiveMerchant #:nodoc:
600
953
  end
601
954
 
602
955
  def order_id_from(raw)
603
- pair = raw.detect { |k, v| k.to_s =~ /_order_code$/ }
956
+ pair = raw.detect { |k, _v| k.to_s =~ /_order_code$/ }
604
957
  (pair ? pair.last : nil)
605
958
  end
606
959
 
607
- def authorization_from_token_details(options={})
960
+ def authorization_from_token_details(options = {})
608
961
  [options[:order_id], options[:token_id], options[:token_scope], options[:customer]].join('|')
609
962
  end
610
963
 
@@ -624,26 +977,34 @@ module ActiveMerchant #:nodoc:
624
977
  token_details
625
978
  end
626
979
 
627
- def payment_details_from(payment_method)
628
- payment_details = {}
629
- if payment_method.respond_to?(:number)
630
- payment_details[:payment_type] = :credit
980
+ def payment_details(payment_method)
981
+ case payment_method
982
+ when String
983
+ token_type_and_details(payment_method)
631
984
  else
632
- token_details = token_details_from_authorization(payment_method)
633
- payment_details.merge!(token_details)
634
- if token_details.has_key?(:token_id)
635
- payment_details[:payment_type] = :token
636
- else
637
- payment_details[:payment_type] = :pay_as_order
638
- end
985
+ type = network_token?(payment_method) ? :network_token : :credit
986
+
987
+ { payment_type: type }
639
988
  end
989
+ end
990
+
991
+ def network_token?(payment_method)
992
+ payment_method.respond_to?(:source) &&
993
+ payment_method.respond_to?(:payment_cryptogram) &&
994
+ payment_method.respond_to?(:eci)
995
+ end
996
+
997
+ def token_type_and_details(token)
998
+ token_details = token_details_from_authorization(token)
999
+ token_details[:payment_type] = token_details.has_key?(:token_id) ? :token : :pay_as_order
640
1000
 
641
- payment_details
1001
+ token_details
642
1002
  end
643
1003
 
644
1004
  def credit_fund_transfer_attribute(options)
645
1005
  return unless options[:credit]
646
- {'action' => 'REFUND'}
1006
+
1007
+ { 'action' => 'REFUND' }
647
1008
  end
648
1009
 
649
1010
  def encoded_credentials
@@ -654,11 +1015,16 @@ module ActiveMerchant #:nodoc:
654
1015
  def currency_exponent(currency)
655
1016
  return 0 if non_fractional_currency?(currency)
656
1017
  return 3 if three_decimal_currency?(currency)
1018
+
657
1019
  return 2
658
1020
  end
659
1021
 
660
- def card_code_for(payment_method)
661
- CARD_CODES[card_brand(payment_method)] || CARD_CODES['unknown']
1022
+ def eligible_for_0_auth?(payment_method, options = {})
1023
+ payment_method.is_a?(CreditCard) && %w(visa master).include?(payment_method.brand) && options[:zero_dollar_auth]
1024
+ end
1025
+
1026
+ def card_holder_name(payment_method, options)
1027
+ test? && options[:execute_threed] && !options[:three_ds_version]&.start_with?('2') ? '3D' : payment_method.name
662
1028
  end
663
1029
  end
664
1030
  end