activemerchant 1.45.0 → 1.126.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (288) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG +2167 -2
  3. data/CONTRIBUTORS +57 -0
  4. data/README.md +62 -41
  5. data/lib/active_merchant/billing/avs_result.rb +25 -28
  6. data/lib/active_merchant/billing/base.rb +11 -35
  7. data/lib/active_merchant/billing/check.rb +28 -24
  8. data/lib/active_merchant/billing/compatibility.rb +10 -12
  9. data/lib/active_merchant/billing/credit_card.rb +141 -69
  10. data/lib/active_merchant/billing/credit_card_formatting.rb +4 -4
  11. data/lib/active_merchant/billing/credit_card_methods.rb +348 -52
  12. data/lib/active_merchant/billing/cvv_result.rb +0 -1
  13. data/lib/active_merchant/billing/gateway.rb +125 -61
  14. data/lib/active_merchant/billing/gateways/adyen.rb +633 -127
  15. data/lib/active_merchant/billing/gateways/airwallex.rb +341 -0
  16. data/lib/active_merchant/billing/gateways/allied_wallet.rb +205 -0
  17. data/lib/active_merchant/billing/gateways/authorize_net.rb +883 -195
  18. data/lib/active_merchant/billing/gateways/authorize_net_arb.rb +31 -24
  19. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +104 -103
  20. data/lib/active_merchant/billing/gateways/axcessms.rb +179 -0
  21. data/lib/active_merchant/billing/gateways/balanced.rb +72 -65
  22. data/lib/active_merchant/billing/gateways/bambora_apac.rb +222 -0
  23. data/lib/active_merchant/billing/gateways/bank_frick.rb +16 -16
  24. data/lib/active_merchant/billing/gateways/banwire.rb +24 -13
  25. data/lib/active_merchant/billing/gateways/barclaycard_smartpay.rb +397 -0
  26. data/lib/active_merchant/billing/gateways/barclays_epdq_extra_plus.rb +7 -7
  27. data/lib/active_merchant/billing/gateways/be2bill.rb +7 -7
  28. data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +143 -62
  29. data/lib/active_merchant/billing/gateways/beanstream.rb +45 -13
  30. data/lib/active_merchant/billing/gateways/beanstream_interac.rb +13 -10
  31. data/lib/active_merchant/billing/gateways/blue_pay.rb +549 -506
  32. data/lib/active_merchant/billing/gateways/blue_snap.rb +623 -0
  33. data/lib/active_merchant/billing/gateways/bogus.rb +82 -36
  34. data/lib/active_merchant/billing/gateways/borgun.rb +61 -40
  35. data/lib/active_merchant/billing/gateways/bpoint.rb +277 -0
  36. data/lib/active_merchant/billing/gateways/braintree/braintree_common.rb +21 -2
  37. data/lib/active_merchant/billing/gateways/braintree/token_nonce.rb +113 -0
  38. data/lib/active_merchant/billing/gateways/braintree.rb +3 -3
  39. data/lib/active_merchant/billing/gateways/braintree_blue.rb +592 -203
  40. data/lib/active_merchant/billing/gateways/braintree_orange.rb +3 -4
  41. data/lib/active_merchant/billing/gateways/bridge_pay.rb +116 -61
  42. data/lib/active_merchant/billing/gateways/cams.rb +230 -0
  43. data/lib/active_merchant/billing/gateways/card_connect.rb +320 -0
  44. data/lib/active_merchant/billing/gateways/card_save.rb +7 -9
  45. data/lib/active_merchant/billing/gateways/card_stream.rb +248 -97
  46. data/lib/active_merchant/billing/gateways/cardknox.rb +327 -0
  47. data/lib/active_merchant/billing/gateways/cardprocess.rb +256 -0
  48. data/lib/active_merchant/billing/gateways/cashnet.rb +70 -26
  49. data/lib/active_merchant/billing/gateways/cc5.rb +14 -17
  50. data/lib/active_merchant/billing/gateways/cecabank.rb +73 -53
  51. data/lib/active_merchant/billing/gateways/cenpos.rb +328 -0
  52. data/lib/active_merchant/billing/gateways/checkout.rb +32 -33
  53. data/lib/active_merchant/billing/gateways/checkout_v2.rb +340 -0
  54. data/lib/active_merchant/billing/gateways/citrus_pay.rb +21 -0
  55. data/lib/active_merchant/billing/gateways/clearhaus.rb +219 -0
  56. data/lib/active_merchant/billing/gateways/commercegate.rb +11 -12
  57. data/lib/active_merchant/billing/gateways/conekta.rb +55 -34
  58. data/lib/active_merchant/billing/gateways/creditcall.rb +272 -0
  59. data/lib/active_merchant/billing/gateways/credorax.rb +506 -0
  60. data/lib/active_merchant/billing/gateways/ct_payment.rb +269 -0
  61. data/lib/active_merchant/billing/gateways/culqi.rb +279 -0
  62. data/lib/active_merchant/billing/gateways/cyber_source.rb +637 -221
  63. data/lib/active_merchant/billing/gateways/d_local.rb +303 -0
  64. data/lib/active_merchant/billing/gateways/data_cash.rb +57 -355
  65. data/lib/active_merchant/billing/gateways/decidir.rb +347 -0
  66. data/lib/active_merchant/billing/gateways/decidir_plus.rb +344 -0
  67. data/lib/active_merchant/billing/gateways/dibs.rb +199 -0
  68. data/lib/active_merchant/billing/gateways/digitzs.rb +295 -0
  69. data/lib/active_merchant/billing/gateways/ebanx.rb +334 -0
  70. data/lib/active_merchant/billing/gateways/efsnet.rb +46 -50
  71. data/lib/active_merchant/billing/gateways/elavon.rb +377 -250
  72. data/lib/active_merchant/billing/gateways/element.rb +386 -0
  73. data/lib/active_merchant/billing/gateways/epay.rb +92 -71
  74. data/lib/active_merchant/billing/gateways/evo_ca.rb +13 -14
  75. data/lib/active_merchant/billing/gateways/eway.rb +85 -73
  76. data/lib/active_merchant/billing/gateways/eway_managed.rb +85 -87
  77. data/lib/active_merchant/billing/gateways/eway_rapid.rb +134 -80
  78. data/lib/active_merchant/billing/gateways/exact.rb +37 -36
  79. data/lib/active_merchant/billing/gateways/ezic.rb +195 -0
  80. data/lib/active_merchant/billing/gateways/fat_zebra.rb +124 -74
  81. data/lib/active_merchant/billing/gateways/federated_canada.rb +11 -13
  82. data/lib/active_merchant/billing/gateways/finansbank.rb +4 -5
  83. data/lib/active_merchant/billing/gateways/first_giving.rb +23 -23
  84. data/lib/active_merchant/billing/gateways/first_pay.rb +45 -23
  85. data/lib/active_merchant/billing/gateways/firstdata_e4.rb +184 -87
  86. data/lib/active_merchant/billing/gateways/firstdata_e4_v27.rb +505 -0
  87. data/lib/active_merchant/billing/gateways/flo2cash.rb +215 -0
  88. data/lib/active_merchant/billing/gateways/flo2cash_simple.rb +20 -0
  89. data/lib/active_merchant/billing/gateways/forte.rb +286 -0
  90. data/lib/active_merchant/billing/gateways/garanti.rb +31 -32
  91. data/lib/active_merchant/billing/gateways/global_collect.rb +507 -0
  92. data/lib/active_merchant/billing/gateways/global_transport.rb +25 -15
  93. data/lib/active_merchant/billing/gateways/hdfc.rb +55 -57
  94. data/lib/active_merchant/billing/gateways/hps.rb +252 -68
  95. data/lib/active_merchant/billing/gateways/iats_payments.rb +99 -38
  96. data/lib/active_merchant/billing/gateways/in_context_paypal_express.rb +15 -0
  97. data/lib/active_merchant/billing/gateways/inspire.rb +48 -48
  98. data/lib/active_merchant/billing/gateways/instapay.rb +10 -14
  99. data/lib/active_merchant/billing/gateways/ipg.rb +415 -0
  100. data/lib/active_merchant/billing/gateways/ipp.rb +176 -0
  101. data/lib/active_merchant/billing/gateways/iridium.rb +254 -244
  102. data/lib/active_merchant/billing/gateways/itransact.rb +14 -14
  103. data/lib/active_merchant/billing/gateways/iveri.rb +254 -0
  104. data/lib/active_merchant/billing/gateways/ixopay.rb +320 -0
  105. data/lib/active_merchant/billing/gateways/jetpay.rb +200 -80
  106. data/lib/active_merchant/billing/gateways/jetpay_v2.rb +432 -0
  107. data/lib/active_merchant/billing/gateways/komoju.rb +115 -0
  108. data/lib/active_merchant/billing/gateways/kushki.rb +277 -0
  109. data/lib/active_merchant/billing/gateways/latitude19.rb +412 -0
  110. data/lib/active_merchant/billing/gateways/linkpoint.rb +95 -85
  111. data/lib/active_merchant/billing/gateways/litle.rb +371 -94
  112. data/lib/active_merchant/billing/gateways/mastercard.rb +293 -0
  113. data/lib/active_merchant/billing/gateways/maxipago.rb +146 -123
  114. data/lib/active_merchant/billing/gateways/mercado_pago.rb +331 -0
  115. data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +47 -23
  116. data/lib/active_merchant/billing/gateways/merchant_one.rb +16 -20
  117. data/lib/active_merchant/billing/gateways/merchant_partners.rb +245 -0
  118. data/lib/active_merchant/billing/gateways/merchant_ware.rb +54 -60
  119. data/lib/active_merchant/billing/gateways/merchant_ware_version_four.rb +60 -44
  120. data/lib/active_merchant/billing/gateways/merchant_warrior.rb +76 -23
  121. data/lib/active_merchant/billing/gateways/mercury.rb +73 -54
  122. data/lib/active_merchant/billing/gateways/metrics_global.rb +33 -43
  123. data/lib/active_merchant/billing/gateways/micropayment.rb +182 -0
  124. data/lib/active_merchant/billing/gateways/migs/migs_codes.rb +7 -7
  125. data/lib/active_merchant/billing/gateways/migs.rb +101 -37
  126. data/lib/active_merchant/billing/gateways/mit.rb +260 -0
  127. data/lib/active_merchant/billing/gateways/modern_payments.rb +3 -3
  128. data/lib/active_merchant/billing/gateways/modern_payments_cim.rb +30 -34
  129. data/lib/active_merchant/billing/gateways/moka.rb +290 -0
  130. data/lib/active_merchant/billing/gateways/monei.rb +422 -0
  131. data/lib/active_merchant/billing/gateways/moneris.rb +236 -72
  132. data/lib/active_merchant/billing/gateways/money_movers.rb +11 -13
  133. data/lib/active_merchant/billing/gateways/mundipagg.rb +363 -0
  134. data/lib/active_merchant/billing/gateways/nab_transact.rb +87 -68
  135. data/lib/active_merchant/billing/gateways/ncr_secure_pay.rb +163 -0
  136. data/lib/active_merchant/billing/gateways/net_registry.rb +12 -12
  137. data/lib/active_merchant/billing/gateways/netaxept.rb +33 -34
  138. data/lib/active_merchant/billing/gateways/netbanx.rb +376 -0
  139. data/lib/active_merchant/billing/gateways/netbilling.rb +82 -43
  140. data/lib/active_merchant/billing/gateways/netpay.rb +10 -10
  141. data/lib/active_merchant/billing/gateways/network_merchants.rb +7 -11
  142. data/lib/active_merchant/billing/gateways/nmi.rb +279 -174
  143. data/lib/active_merchant/billing/gateways/ogone.rb +96 -50
  144. data/lib/active_merchant/billing/gateways/omise.rb +323 -0
  145. data/lib/active_merchant/billing/gateways/openpay.rb +58 -23
  146. data/lib/active_merchant/billing/gateways/opp.rb +394 -0
  147. data/lib/active_merchant/billing/gateways/optimal_payment.rb +87 -69
  148. data/lib/active_merchant/billing/gateways/orbital/orbital_soft_descriptors.rb +5 -7
  149. data/lib/active_merchant/billing/gateways/orbital.rb +771 -328
  150. data/lib/active_merchant/billing/gateways/pac_net_raven.rb +31 -32
  151. data/lib/active_merchant/billing/gateways/pagarme.rb +239 -0
  152. data/lib/active_merchant/billing/gateways/pago_facil.rb +12 -14
  153. data/lib/active_merchant/billing/gateways/pay_arc.rb +392 -0
  154. data/lib/active_merchant/billing/gateways/pay_conex.rb +245 -0
  155. data/lib/active_merchant/billing/gateways/pay_gate_xml.rb +84 -68
  156. data/lib/active_merchant/billing/gateways/pay_hub.rb +213 -0
  157. data/lib/active_merchant/billing/gateways/pay_junction.rb +37 -37
  158. data/lib/active_merchant/billing/gateways/pay_junction_v2.rb +206 -0
  159. data/lib/active_merchant/billing/gateways/pay_secure.rb +15 -17
  160. data/lib/active_merchant/billing/gateways/pay_trace.rb +404 -0
  161. data/lib/active_merchant/billing/gateways/paybox_direct.rb +85 -49
  162. data/lib/active_merchant/billing/gateways/payeezy.rb +458 -0
  163. data/lib/active_merchant/billing/gateways/payex.rb +39 -42
  164. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +67 -41
  165. data/lib/active_merchant/billing/gateways/payflow/payflow_express_response.rb +11 -8
  166. data/lib/active_merchant/billing/gateways/payflow/payflow_response.rb +3 -3
  167. data/lib/active_merchant/billing/gateways/payflow.rb +215 -46
  168. data/lib/active_merchant/billing/gateways/payflow_express.rb +64 -68
  169. data/lib/active_merchant/billing/gateways/payflow_express_uk.rb +2 -3
  170. data/lib/active_merchant/billing/gateways/payflow_uk.rb +5 -6
  171. data/lib/active_merchant/billing/gateways/payment_express.rb +78 -58
  172. data/lib/active_merchant/billing/gateways/paymentez.rb +353 -0
  173. data/lib/active_merchant/billing/gateways/paymill.rb +163 -75
  174. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +55 -7
  175. data/lib/active_merchant/billing/gateways/paypal/paypal_recurring_api.rb +1 -1
  176. data/lib/active_merchant/billing/gateways/paypal.rb +37 -18
  177. data/lib/active_merchant/billing/gateways/paypal_ca.rb +2 -2
  178. data/lib/active_merchant/billing/gateways/paypal_digital_goods.rb +5 -5
  179. data/lib/active_merchant/billing/gateways/paypal_express.rb +12 -6
  180. data/lib/active_merchant/billing/gateways/paypal_express_common.rb +3 -3
  181. data/lib/active_merchant/billing/gateways/paysafe.rb +412 -0
  182. data/lib/active_merchant/billing/gateways/payscout.rb +10 -13
  183. data/lib/active_merchant/billing/gateways/paystation.rb +96 -91
  184. data/lib/active_merchant/billing/gateways/payu_in.rb +249 -0
  185. data/lib/active_merchant/billing/gateways/payu_latam.rb +479 -0
  186. data/lib/active_merchant/billing/gateways/payway.rb +27 -27
  187. data/lib/active_merchant/billing/gateways/payway_dot_com.rb +253 -0
  188. data/lib/active_merchant/billing/gateways/pin.rb +113 -37
  189. data/lib/active_merchant/billing/gateways/plugnpay.rb +82 -82
  190. data/lib/active_merchant/billing/gateways/priority.rb +369 -0
  191. data/lib/active_merchant/billing/gateways/pro_pay.rb +325 -0
  192. data/lib/active_merchant/billing/gateways/psigate.rb +55 -44
  193. data/lib/active_merchant/billing/gateways/psl_card.rb +32 -40
  194. data/lib/active_merchant/billing/gateways/qbms.rb +86 -76
  195. data/lib/active_merchant/billing/gateways/quantum.rb +21 -23
  196. data/lib/active_merchant/billing/gateways/quickbooks.rb +377 -0
  197. data/lib/active_merchant/billing/gateways/quickpay/quickpay_common.rb +184 -0
  198. data/lib/active_merchant/billing/gateways/quickpay/quickpay_v10.rb +297 -0
  199. data/lib/active_merchant/billing/gateways/quickpay/quickpay_v4to7.rb +226 -0
  200. data/lib/active_merchant/billing/gateways/quickpay.rb +10 -353
  201. data/lib/active_merchant/billing/gateways/qvalent.rb +305 -0
  202. data/lib/active_merchant/billing/gateways/rapyd.rb +258 -0
  203. data/lib/active_merchant/billing/gateways/realex.rb +154 -52
  204. data/lib/active_merchant/billing/gateways/redsys.rb +488 -161
  205. data/lib/active_merchant/billing/gateways/s5.rb +247 -0
  206. data/lib/active_merchant/billing/gateways/safe_charge.rb +298 -0
  207. data/lib/active_merchant/billing/gateways/sage.rb +404 -133
  208. data/lib/active_merchant/billing/gateways/sage_pay.rb +145 -109
  209. data/lib/active_merchant/billing/gateways/sallie_mae.rb +13 -15
  210. data/lib/active_merchant/billing/gateways/secure_net.rb +62 -54
  211. data/lib/active_merchant/billing/gateways/secure_pay.rb +32 -42
  212. data/lib/active_merchant/billing/gateways/secure_pay_au.rb +36 -27
  213. data/lib/active_merchant/billing/gateways/secure_pay_tech.rb +14 -16
  214. data/lib/active_merchant/billing/gateways/securion_pay.rb +265 -0
  215. data/lib/active_merchant/billing/gateways/simetrik.rb +362 -0
  216. data/lib/active_merchant/billing/gateways/skip_jack.rb +52 -54
  217. data/lib/active_merchant/billing/gateways/smart_ps.rb +51 -60
  218. data/lib/active_merchant/billing/gateways/so_easy_pay.rb +29 -29
  219. data/lib/active_merchant/billing/gateways/spreedly_core.rb +108 -43
  220. data/lib/active_merchant/billing/gateways/stripe.rb +536 -120
  221. data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +516 -0
  222. data/lib/active_merchant/billing/gateways/swipe_checkout.rb +19 -25
  223. data/lib/active_merchant/billing/gateways/telr.rb +273 -0
  224. data/lib/active_merchant/billing/gateways/tns.rb +16 -217
  225. data/lib/active_merchant/billing/gateways/trans_first.rb +148 -34
  226. data/lib/active_merchant/billing/gateways/trans_first_transaction_express.rb +612 -0
  227. data/lib/active_merchant/billing/gateways/transact_pro.rb +222 -0
  228. data/lib/active_merchant/billing/gateways/transax.rb +6 -8
  229. data/lib/active_merchant/billing/gateways/transnational.rb +1 -2
  230. data/lib/active_merchant/billing/gateways/trexle.rb +221 -0
  231. data/lib/active_merchant/billing/gateways/trust_commerce.rb +162 -89
  232. data/lib/active_merchant/billing/gateways/usa_epay.rb +5 -6
  233. data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +332 -236
  234. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +185 -72
  235. data/lib/active_merchant/billing/gateways/vanco.rb +294 -0
  236. data/lib/active_merchant/billing/gateways/verifi.rb +52 -53
  237. data/lib/active_merchant/billing/gateways/viaklix.rb +19 -31
  238. data/lib/active_merchant/billing/gateways/visanet_peru.rb +250 -0
  239. data/lib/active_merchant/billing/gateways/vpos.rb +220 -0
  240. data/lib/active_merchant/billing/gateways/webpay.rb +9 -9
  241. data/lib/active_merchant/billing/gateways/wepay.rb +108 -62
  242. data/lib/active_merchant/billing/gateways/wirecard.rb +52 -43
  243. data/lib/active_merchant/billing/gateways/wompi.rb +193 -0
  244. data/lib/active_merchant/billing/gateways/world_net.rb +345 -0
  245. data/lib/active_merchant/billing/gateways/worldpay.rb +725 -121
  246. data/lib/active_merchant/billing/gateways/worldpay_online_payments.rb +208 -0
  247. data/lib/active_merchant/billing/gateways/worldpay_us.rb +79 -39
  248. data/lib/active_merchant/billing/gateways.rb +8 -11
  249. data/lib/active_merchant/billing/model.rb +2 -2
  250. data/lib/active_merchant/billing/network_tokenization_credit_card.rb +39 -0
  251. data/lib/active_merchant/billing/payment_token.rb +1 -1
  252. data/lib/active_merchant/billing/rails.rb +1 -1
  253. data/lib/active_merchant/billing/response.rb +19 -13
  254. data/lib/active_merchant/billing/three_d_secure_eci_mapper.rb +27 -0
  255. data/lib/active_merchant/billing.rb +3 -0
  256. data/lib/active_merchant/connection.rb +196 -0
  257. data/lib/active_merchant/country.rb +13 -8
  258. data/lib/active_merchant/errors.rb +6 -0
  259. data/lib/active_merchant/net_http_ssl_connection.rb +11 -0
  260. data/lib/active_merchant/network_connection_retries.rb +78 -0
  261. data/lib/active_merchant/post_data.rb +26 -0
  262. data/lib/active_merchant/posts_data.rb +92 -0
  263. data/lib/active_merchant/version.rb +1 -1
  264. data/lib/active_merchant.rb +14 -59
  265. data/lib/activemerchant.rb +1 -1
  266. data/lib/certs/cacert.pem +3214 -0
  267. data/lib/support/gateway_support.rb +8 -10
  268. data/lib/support/outbound_hosts.rb +13 -10
  269. data/lib/support/ssl_verify.rb +9 -14
  270. data/lib/support/ssl_version.rb +86 -0
  271. metadata +136 -94
  272. checksums.yaml.gz.sig +0 -1
  273. data/lib/active_merchant/billing/gateways/app55.rb +0 -176
  274. data/lib/active_merchant/billing/gateways/barclays_epdq.rb +0 -314
  275. data/lib/active_merchant/billing/gateways/certo_direct.rb +0 -278
  276. data/lib/active_merchant/billing/gateways/ideal/ideal_base.rb +0 -246
  277. data/lib/active_merchant/billing/gateways/ideal/ideal_rabobank.pem +0 -13
  278. data/lib/active_merchant/billing/gateways/ideal/ideal_response.rb +0 -29
  279. data/lib/active_merchant/billing/gateways/ideal_rabobank.rb +0 -66
  280. data/lib/active_merchant/billing/gateways/moneris_us.rb +0 -291
  281. data/lib/active_merchant/billing/gateways/sage/sage_bankcard.rb +0 -87
  282. data/lib/active_merchant/billing/gateways/sage/sage_core.rb +0 -114
  283. data/lib/active_merchant/billing/gateways/sage/sage_vault.rb +0 -149
  284. data/lib/active_merchant/billing/gateways/sage/sage_virtual_check.rb +0 -102
  285. data/lib/active_merchant/billing/gateways/vindicia.rb +0 -385
  286. data/lib/active_merchant/offsite_payments_shim.rb +0 -19
  287. data.tar.gz.sig +0 -0
  288. metadata.gz.sig +0 -0
@@ -1,12 +1,14 @@
1
- require File.dirname(__FILE__) + '/braintree/braintree_common'
1
+ require 'active_merchant/billing/gateways/braintree/braintree_common'
2
+ require 'active_merchant/billing/gateways/braintree/token_nonce'
3
+ require 'active_support/core_ext/array/extract_options'
2
4
 
3
5
  begin
4
- require "braintree"
6
+ require 'braintree'
5
7
  rescue LoadError
6
- raise "Could not load the braintree gem. Use `gem install braintree` to install it."
8
+ raise 'Could not load the braintree gem. Use `gem install braintree` to install it.'
7
9
  end
8
10
 
9
- raise "Need braintree gem 2.x.y. Run `gem install braintree --version '~>2.0'` to get the correct version." unless Braintree::Version::Major == 2
11
+ raise 'Need braintree gem >= 2.0.0.' unless Braintree::Version::Major >= 2 && Braintree::Version::Minor >= 0
10
12
 
11
13
  module ActiveMerchant #:nodoc:
12
14
  module Billing #:nodoc:
@@ -37,17 +39,24 @@ module ActiveMerchant #:nodoc:
37
39
  #
38
40
  class BraintreeBlueGateway < Gateway
39
41
  include BraintreeCommon
42
+ include Empty
40
43
 
41
44
  self.display_name = 'Braintree (Blue Platform)'
42
45
 
46
+ ERROR_CODES = {
47
+ cannot_refund_if_unsettled: 91506
48
+ }
49
+
50
+ DIRECT_BANK_ERROR = 'Direct bank account transactions are not supported. Bank accounts must be successfully stored before use.'.freeze
51
+
43
52
  def initialize(options = {})
44
53
  requires!(options, :merchant_id, :public_key, :private_key)
45
54
  @merchant_account_id = options[:merchant_account_id]
46
55
 
47
56
  super
48
57
 
49
- if wiredump_device
50
- logger = ((Logger === wiredump_device) ? wiredump_device : Logger.new(wiredump_device))
58
+ if wiredump_device.present?
59
+ logger = (Logger === wiredump_device ? wiredump_device : Logger.new(wiredump_device))
51
60
  logger.level = Logger::DEBUG
52
61
  else
53
62
  logger = Braintree::Configuration.logger.clone
@@ -55,30 +64,32 @@ module ActiveMerchant #:nodoc:
55
64
  end
56
65
 
57
66
  @configuration = Braintree::Configuration.new(
58
- :merchant_id => options[:merchant_id],
59
- :public_key => options[:public_key],
60
- :private_key => options[:private_key],
61
- :environment => (options[:environment] || (test? ? :sandbox : :production)).to_sym,
62
- :custom_user_agent => "ActiveMerchant #{ActiveMerchant::VERSION}",
63
- :logger => logger,
67
+ merchant_id: options[:merchant_id],
68
+ public_key: options[:public_key],
69
+ private_key: options[:private_key],
70
+ environment: (options[:environment] || (test? ? :sandbox : :production)).to_sym,
71
+ custom_user_agent: "ActiveMerchant #{ActiveMerchant::VERSION}",
72
+ logger: options[:logger] || logger
64
73
  )
65
74
 
66
- @braintree_gateway = Braintree::Gateway.new( @configuration )
75
+ @braintree_gateway = Braintree::Gateway.new(@configuration)
67
76
  end
68
77
 
69
78
  def authorize(money, credit_card_or_vault_id, options = {})
79
+ return Response.new(false, DIRECT_BANK_ERROR) if credit_card_or_vault_id.is_a? Check
80
+
70
81
  create_transaction(:sale, money, credit_card_or_vault_id, options)
71
82
  end
72
83
 
73
84
  def capture(money, authorization, options = {})
74
85
  commit do
75
- result = @braintree_gateway.transaction.submit_for_settlement(authorization, amount(money).to_s)
86
+ result = @braintree_gateway.transaction.submit_for_settlement(authorization, localized_amount(money, options[:currency] || default_currency).to_s)
76
87
  response_from_result(result)
77
88
  end
78
89
  end
79
90
 
80
91
  def purchase(money, credit_card_or_vault_id, options = {})
81
- authorize(money, credit_card_or_vault_id, options.merge(:submit_for_settlement => true))
92
+ authorize(money, credit_card_or_vault_id, options.merge(submit_for_settlement: true))
82
93
  end
83
94
 
84
95
  def credit(money, credit_card_or_vault_id, options = {})
@@ -88,11 +99,18 @@ module ActiveMerchant #:nodoc:
88
99
  def refund(*args)
89
100
  # legacy signature: #refund(transaction_id, options = {})
90
101
  # new signature: #refund(money, transaction_id, options = {})
91
- money, transaction_id, _ = extract_refund_args(args)
92
- money = amount(money).to_s if money
102
+ money, transaction_id, options = extract_refund_args(args)
103
+ money = localized_amount(money, options[:currency] || default_currency).to_s if money
93
104
 
94
105
  commit do
95
- response_from_result(@braintree_gateway.transaction.refund(transaction_id, money))
106
+ response = response_from_result(@braintree_gateway.transaction.refund(transaction_id, money))
107
+
108
+ if !response.success? && options[:force_full_refund_if_unsettled] &&
109
+ response.message =~ /#{ERROR_CODES[:cannot_refund_if_unsettled]}/
110
+ void(transaction_id)
111
+ else
112
+ response
113
+ end
96
114
  end
97
115
  end
98
116
 
@@ -102,111 +120,153 @@ module ActiveMerchant #:nodoc:
102
120
  end
103
121
  end
104
122
 
105
- def verify(credit_card, options = {})
106
- MultiResponse.run(:use_first_response) do |r|
107
- r.process { authorize(100, credit_card, options) }
108
- r.process(:ignore_result) { void(r.authorization, options) }
123
+ def verify(creditcard, options = {})
124
+ if options[:allow_card_verification] == true
125
+ options.delete(:allow_card_verification)
126
+ exp_month = creditcard.month.to_s
127
+ exp_year = creditcard.year.to_s
128
+ expiration = "#{exp_month}/#{exp_year}"
129
+ payload = {
130
+ credit_card: {
131
+ number: creditcard.number,
132
+ expiration_date: expiration,
133
+ cvv: creditcard.verification_value,
134
+ billing_address: {
135
+ postal_code: options[:billing_address][:zip]
136
+ }
137
+ }
138
+ }
139
+ commit do
140
+ result = @braintree_gateway.verification.create(payload)
141
+ response = Response.new(result.success?, message_from_transaction_result(result), response_options(result))
142
+ response.cvv_result['message'] = ''
143
+ response.cvv_result['code'] = response.params['cvv_result'] if response.params['cvv_result']
144
+ response.avs_result['code'] = response.params['avs_result'][:code] if response.params.dig('avs_result', :code)
145
+ response
146
+ end
147
+
148
+ else
149
+ MultiResponse.run(:use_first_response) do |r|
150
+ r.process { authorize(100, creditcard, options) }
151
+ r.process(:ignore_result) { void(r.authorization, options) }
152
+ end
109
153
  end
110
154
  end
111
155
 
112
- def store(creditcard, options = {})
113
- if options[:customer].present?
114
- MultiResponse.new.tap do |r|
115
- customer_exists_response = nil
116
- r.process{customer_exists_response = check_customer_exists(options[:customer])}
117
- r.process do
118
- if customer_exists_response.params["exists"]
119
- add_credit_card_to_customer(creditcard, options)
120
- else
121
- add_customer_with_credit_card(creditcard, options)
122
- end
123
- end
124
- end
125
- else
126
- add_customer_with_credit_card(creditcard, options)
156
+ def store(payment_method, options = {})
157
+ return Response.new(false, bank_account_errors(payment_method, options)) if payment_method.is_a?(Check) && bank_account_errors(payment_method, options).present?
158
+
159
+ MultiResponse.run do |r|
160
+ r.process { check_customer_exists(options[:customer]) }
161
+ process_by = payment_method.is_a?(Check) ? :store_bank_account : :store_credit_card
162
+ send process_by, payment_method, options, r
127
163
  end
128
164
  end
129
165
 
130
166
  def update(vault_id, creditcard, options = {})
131
167
  braintree_credit_card = nil
132
168
  commit do
133
- braintree_credit_card = @braintree_gateway.customer.find(vault_id).credit_cards.detect { |cc| cc.default? }
169
+ braintree_credit_card = @braintree_gateway.customer.find(vault_id).credit_cards.detect(&:default?)
134
170
  return Response.new(false, 'Braintree::NotFoundError') if braintree_credit_card.nil?
135
171
 
136
- options.merge!(:update_existing_token => braintree_credit_card.token)
172
+ options[:update_existing_token] = braintree_credit_card.token
137
173
  credit_card_params = merge_credit_card_options({
138
- :credit_card => {
139
- :cardholder_name => creditcard.name,
140
- :number => creditcard.number,
141
- :cvv => creditcard.verification_value,
142
- :expiration_month => creditcard.month.to_s.rjust(2, "0"),
143
- :expiration_year => creditcard.year.to_s
174
+ credit_card: {
175
+ cardholder_name: creditcard.name,
176
+ number: creditcard.number,
177
+ cvv: creditcard.verification_value,
178
+ expiration_month: creditcard.month.to_s.rjust(2, '0'),
179
+ expiration_year: creditcard.year.to_s
144
180
  }
145
181
  }, options)[:credit_card]
146
182
 
147
183
  result = @braintree_gateway.customer.update(vault_id,
148
- :first_name => creditcard.first_name,
149
- :last_name => creditcard.last_name,
150
- :email => scrub_email(options[:email]),
151
- :credit_card => credit_card_params
152
- )
184
+ first_name: creditcard.first_name,
185
+ last_name: creditcard.last_name,
186
+ email: scrub_email(options[:email]),
187
+ phone: options[:phone] || (options[:billing_address][:phone] if options[:billing_address] &&
188
+ options[:billing_address][:phone]),
189
+ credit_card: credit_card_params)
153
190
  Response.new(result.success?, message_from_result(result),
154
- :braintree_customer => (customer_hash(@braintree_gateway.customer.find(vault_id), :include_credit_cards) if result.success?),
155
- :customer_vault_id => (result.customer.id if result.success?)
156
- )
191
+ braintree_customer: (customer_hash(@braintree_gateway.customer.find(vault_id), :include_credit_cards) if result.success?),
192
+ customer_vault_id: (result.customer.id if result.success?))
157
193
  end
158
194
  end
159
195
 
160
196
  def unstore(customer_vault_id, options = {})
161
197
  commit do
162
- if(!customer_vault_id && options[:credit_card_token])
198
+ if !customer_vault_id && options[:credit_card_token]
163
199
  @braintree_gateway.credit_card.delete(options[:credit_card_token])
164
200
  else
165
201
  @braintree_gateway.customer.delete(customer_vault_id)
166
202
  end
167
- Response.new(true, "OK")
203
+ Response.new(true, 'OK')
168
204
  end
169
205
  end
170
- alias_method :delete, :unstore
206
+ alias delete unstore
207
+
208
+ def supports_network_tokenization?
209
+ true
210
+ end
211
+
212
+ def verify_credentials
213
+ begin
214
+ @braintree_gateway.transaction.find('non_existent_token')
215
+ rescue Braintree::AuthenticationError
216
+ return false
217
+ rescue Braintree::NotFoundError
218
+ return true
219
+ end
220
+
221
+ true
222
+ end
171
223
 
172
224
  private
173
225
 
174
226
  def check_customer_exists(customer_vault_id)
227
+ return Response.new true, 'Customer not found', { exists: false } if customer_vault_id.blank?
228
+
175
229
  commit do
176
- begin
177
- @braintree_gateway.customer.find(customer_vault_id)
178
- ActiveMerchant::Billing::Response.new(true, "Customer found", {exists: true}, authorization: customer_vault_id)
179
- rescue Braintree::NotFoundError
180
- ActiveMerchant::Billing::Response.new(true, "Customer not found", {exists: false})
181
- end
230
+ @braintree_gateway.customer.find(customer_vault_id)
231
+ ActiveMerchant::Billing::Response.new(true, 'Customer found', { exists: true }, authorization: customer_vault_id)
232
+ rescue Braintree::NotFoundError
233
+ ActiveMerchant::Billing::Response.new(true, 'Customer not found', { exists: false })
182
234
  end
183
235
  end
184
236
 
185
237
  def add_customer_with_credit_card(creditcard, options)
186
238
  commit do
187
- parameters = {
188
- :first_name => creditcard.first_name,
189
- :last_name => creditcard.last_name,
190
- :email => scrub_email(options[:email]),
191
- :id => options[:customer],
192
- :credit_card => {
193
- :cardholder_name => creditcard.name,
194
- :number => creditcard.number,
195
- :cvv => creditcard.verification_value,
196
- :expiration_month => creditcard.month.to_s.rjust(2, "0"),
197
- :expiration_year => creditcard.year.to_s,
198
- :token => options[:credit_card_token]
239
+ if options[:payment_method_nonce]
240
+ credit_card_params = { payment_method_nonce: options[:payment_method_nonce] }
241
+ else
242
+ credit_card_params = {
243
+ credit_card: {
244
+ cardholder_name: creditcard.name,
245
+ number: creditcard.number,
246
+ cvv: creditcard.verification_value,
247
+ expiration_month: creditcard.month.to_s.rjust(2, '0'),
248
+ expiration_year: creditcard.year.to_s,
249
+ token: options[:credit_card_token]
250
+ }
199
251
  }
200
- }
252
+ end
253
+ parameters = {
254
+ first_name: creditcard.first_name,
255
+ last_name: creditcard.last_name,
256
+ email: scrub_email(options[:email]),
257
+ phone: options[:phone] || (options[:billing_address][:phone] if options[:billing_address] &&
258
+ options[:billing_address][:phone]),
259
+ id: options[:customer],
260
+ device_data: options[:device_data]
261
+ }.merge credit_card_params
201
262
  result = @braintree_gateway.customer.create(merge_credit_card_options(parameters, options))
202
263
  Response.new(result.success?, message_from_result(result),
203
264
  {
204
- :braintree_customer => (customer_hash(result.customer, :include_credit_cards) if result.success?),
205
- :customer_vault_id => (result.customer.id if result.success?),
206
- :credit_card_token => (result.customer.credit_cards[0].token if result.success?)
265
+ braintree_customer: (customer_hash(result.customer, :include_credit_cards) if result.success?),
266
+ customer_vault_id: (result.customer.id if result.success?),
267
+ credit_card_token: (result.customer.credit_cards[0].token if result.success?)
207
268
  },
208
- :authorization => (result.customer.id if result.success?)
209
- )
269
+ authorization: (result.customer.id if result.success?))
210
270
  end
211
271
  end
212
272
 
@@ -218,10 +278,14 @@ module ActiveMerchant #:nodoc:
218
278
  cardholder_name: credit_card.name,
219
279
  number: credit_card.number,
220
280
  cvv: credit_card.verification_value,
221
- expiration_month: credit_card.month.to_s.rjust(2, "0"),
281
+ expiration_month: credit_card.month.to_s.rjust(2, '0'),
222
282
  expiration_year: credit_card.year.to_s,
283
+ device_data: options[:device_data]
223
284
  }
224
- parameters[:billing_address] = map_address(options[:billing_address]) if options[:billing_address]
285
+ if options[:billing_address]
286
+ address = map_address(options[:billing_address])
287
+ parameters[:billing_address] = address unless address.all? { |_k, v| empty?(v) }
288
+ end
225
289
 
226
290
  result = @braintree_gateway.credit_card.create(parameters)
227
291
  ActiveMerchant::Billing::Response.new(
@@ -238,57 +302,55 @@ module ActiveMerchant #:nodoc:
238
302
 
239
303
  def scrub_email(email)
240
304
  return nil unless email.present?
241
- return nil if (
305
+ return nil if
242
306
  email !~ /^.+@[^\.]+(\.[^\.]+)+[a-z]$/i ||
243
307
  email =~ /\.(con|met)$/i
244
- )
308
+
245
309
  email
246
310
  end
247
311
 
248
312
  def scrub_zip(zip)
249
313
  return nil unless zip.present?
250
- return nil if(
314
+ return nil if
251
315
  zip.gsub(/[^a-z0-9]/i, '').length > 9 ||
252
316
  zip =~ /[^a-z0-9\- ]/i
253
- )
317
+
254
318
  zip
255
319
  end
256
320
 
257
321
  def merge_credit_card_options(parameters, options)
258
322
  valid_options = {}
259
323
  options.each do |key, value|
260
- valid_options[key] = value if [:update_existing_token, :verify_card, :verification_merchant_account_id].include?(key)
324
+ valid_options[key] = value if %i[update_existing_token verify_card verification_merchant_account_id].include?(key)
261
325
  end
262
326
 
263
- if valid_options.include?(:verify_card) && @merchant_account_id
264
- valid_options[:verification_merchant_account_id] ||= @merchant_account_id
265
- end
327
+ valid_options[:verification_merchant_account_id] ||= @merchant_account_id if valid_options.include?(:verify_card) && @merchant_account_id
266
328
 
267
329
  parameters[:credit_card] ||= {}
268
- parameters[:credit_card].merge!(:options => valid_options)
269
- parameters[:credit_card][:billing_address] = map_address(options[:billing_address]) if options[:billing_address]
330
+ parameters[:credit_card][:options] = valid_options
331
+ if options[:billing_address]
332
+ address = map_address(options[:billing_address])
333
+ parameters[:credit_card][:billing_address] = address unless address.all? { |_k, v| empty?(v) }
334
+ end
270
335
  parameters
271
336
  end
272
337
 
273
338
  def map_address(address)
274
- return {} if address.nil?
275
339
  mapped = {
276
- :street_address => address[:address1],
277
- :extended_address => address[:address2],
278
- :company => address[:company],
279
- :locality => address[:city],
280
- :region => address[:state],
281
- :postal_code => scrub_zip(address[:zip]),
340
+ street_address: address[:address1],
341
+ extended_address: address[:address2],
342
+ company: address[:company],
343
+ locality: address[:city],
344
+ region: address[:state],
345
+ postal_code: scrub_zip(address[:zip])
282
346
  }
283
- if(address[:country] || address[:country_code_alpha2])
284
- mapped[:country_code_alpha2] = (address[:country] || address[:country_code_alpha2])
285
- elsif address[:country_name]
286
- mapped[:country_name] = address[:country_name]
287
- elsif address[:country_code_alpha3]
288
- mapped[:country_code_alpha3] = address[:country_code_alpha3]
289
- elsif address[:country_code_numeric]
290
- mapped[:country_code_numeric] = address[:country_code_numeric]
291
- end
347
+
348
+ mapped[:country_code_alpha2] = (address[:country] || address[:country_code_alpha2]) if address[:country] || address[:country_code_alpha2]
349
+ mapped[:country_name] = address[:country_name] if address[:country_name]
350
+ mapped[:country_code_alpha3] = address[:country_code_alpha3] if address[:country_code_alpha3]
351
+ mapped[:country_code_alpha3] ||= Country.find(address[:country]).code(:alpha3).value unless address[:country].blank?
352
+ mapped[:country_code_numeric] = address[:country_code_numeric] if address[:country_code_numeric]
353
+
292
354
  mapped
293
355
  end
294
356
 
@@ -300,49 +362,94 @@ module ActiveMerchant #:nodoc:
300
362
 
301
363
  def message_from_result(result)
302
364
  if result.success?
303
- "OK"
304
- elsif result.errors.size == 0 && result.credit_card_verification
365
+ 'OK'
366
+ elsif result.errors.any?
367
+ result.errors.map { |e| "#{e.message} (#{e.code})" }.join(' ')
368
+ elsif result.credit_card_verification
305
369
  "Processor declined: #{result.credit_card_verification.processor_response_text} (#{result.credit_card_verification.processor_response_code})"
306
370
  else
307
- result.errors.map { |e| "#{e.message} (#{e.code})" }.join(" ")
371
+ result.message.to_s
308
372
  end
309
373
  end
310
374
 
311
375
  def response_from_result(result)
312
- Response.new(result.success?, message_from_result(result),
313
- { braintree_transaction: (transaction_hash(result.transaction) if result.success?) },
314
- { authorization: (result.transaction.id if result.success?) }
315
- )
376
+ response_hash = { braintree_transaction: transaction_hash(result) }
377
+
378
+ Response.new(
379
+ result.success?,
380
+ message_from_result(result),
381
+ response_hash,
382
+ authorization: result.transaction&.id,
383
+ test: test?
384
+ )
316
385
  end
317
386
 
318
387
  def response_params(result)
319
388
  params = {}
320
- if result.success?
321
- params[:braintree_transaction] = transaction_hash(result.transaction)
322
- params[:customer_vault_id] = result.transaction.customer_details.id
323
- end
389
+ params[:customer_vault_id] = result.transaction.customer_details.id if result.success?
390
+ params[:braintree_transaction] = transaction_hash(result)
324
391
  params
325
392
  end
326
393
 
327
394
  def response_options(result)
328
395
  options = {}
329
- if result.success?
396
+ if result.credit_card_verification
397
+ options[:authorization] = result.credit_card_verification.id
398
+ options[:avs_result] = { code: avs_code_from(result.credit_card_verification) }
399
+ options[:cvv_result] = result.credit_card_verification.cvv_response_code
400
+ elsif result.transaction
330
401
  options[:authorization] = result.transaction.id
331
- end
332
- if result.transaction
333
- options[:avs_result] = {
334
- :code => nil, :message => nil,
335
- :street_match => result.transaction.avs_street_address_response_code,
336
- :postal_match => result.transaction.avs_postal_code_response_code
337
- }
402
+ options[:avs_result] = { code: avs_code_from(result.transaction) }
338
403
  options[:cvv_result] = result.transaction.cvv_response_code
339
404
  end
405
+ options[:test] = test?
340
406
  options
341
407
  end
342
408
 
409
+ def avs_code_from(transaction)
410
+ transaction.avs_error_response_code ||
411
+ avs_mapping["street: #{transaction.avs_street_address_response_code}, zip: #{transaction.avs_postal_code_response_code}"]
412
+ end
413
+
414
+ def avs_mapping
415
+ {
416
+ 'street: M, zip: M' => 'M',
417
+ 'street: M, zip: N' => 'A',
418
+ 'street: M, zip: U' => 'B',
419
+ 'street: M, zip: I' => 'B',
420
+ 'street: M, zip: A' => 'B',
421
+
422
+ 'street: N, zip: M' => 'Z',
423
+ 'street: N, zip: N' => 'C',
424
+ 'street: N, zip: U' => 'C',
425
+ 'street: N, zip: I' => 'C',
426
+ 'street: N, zip: A' => 'C',
427
+
428
+ 'street: U, zip: M' => 'P',
429
+ 'street: U, zip: N' => 'N',
430
+ 'street: U, zip: U' => 'I',
431
+ 'street: U, zip: I' => 'I',
432
+ 'street: U, zip: A' => 'I',
433
+
434
+ 'street: I, zip: M' => 'P',
435
+ 'street: I, zip: N' => 'C',
436
+ 'street: I, zip: U' => 'I',
437
+ 'street: I, zip: I' => 'I',
438
+ 'street: I, zip: A' => 'I',
439
+
440
+ 'street: A, zip: M' => 'P',
441
+ 'street: A, zip: N' => 'C',
442
+ 'street: A, zip: U' => 'I',
443
+ 'street: A, zip: I' => 'I',
444
+ 'street: A, zip: A' => 'I',
445
+
446
+ 'street: B, zip: B' => 'B'
447
+ }
448
+ end
449
+
343
450
  def message_from_transaction_result(result)
344
- if result.transaction && result.transaction.status == "gateway_rejected"
345
- "Transaction declined - gateway rejected"
451
+ if result.transaction && result.transaction.status == 'gateway_rejected'
452
+ 'Transaction declined - gateway rejected'
346
453
  elsif result.transaction
347
454
  "#{result.transaction.processor_response_code} #{result.transaction.processor_response_text}"
348
455
  else
@@ -350,6 +457,16 @@ module ActiveMerchant #:nodoc:
350
457
  end
351
458
  end
352
459
 
460
+ def response_code_from_result(result)
461
+ if result.transaction
462
+ result.transaction.processor_response_code
463
+ elsif result.errors.size == 0 && result.credit_card_verification
464
+ result.credit_card_verification.processor_response_code
465
+ elsif result.errors.size > 0
466
+ result.errors.first.code
467
+ end
468
+ end
469
+
353
470
  def create_transaction(transaction_type, money, credit_card_or_vault_id, options)
354
471
  transaction_params = create_transaction_parameters(money, credit_card_or_vault_id, options)
355
472
  commit do
@@ -373,24 +490,24 @@ module ActiveMerchant #:nodoc:
373
490
  end
374
491
  end
375
492
 
376
- def customer_hash(customer, include_credit_cards=false)
493
+ def customer_hash(customer, include_credit_cards = false)
377
494
  hash = {
378
- "email" => customer.email,
379
- "first_name" => customer.first_name,
380
- "last_name" => customer.last_name,
381
- "id" => customer.id
495
+ 'email' => customer.email,
496
+ 'phone' => customer.phone,
497
+ 'first_name' => customer.first_name,
498
+ 'last_name' => customer.last_name,
499
+ 'id' => customer.id
382
500
  }
383
501
 
384
502
  if include_credit_cards
385
- hash["credit_cards"] = customer.credit_cards.map do |cc|
503
+ hash['credit_cards'] = customer.credit_cards.map do |cc|
386
504
  {
387
- "bin" => cc.bin,
388
- "expiration_date" => cc.expiration_date,
389
- "token" => cc.token,
390
- "last_4" => cc.last_4,
391
- "card_type" => cc.card_type,
392
- "masked_number" => cc.masked_number,
393
- "token" => cc.token
505
+ 'bin' => cc.bin,
506
+ 'expiration_date' => cc.expiration_date,
507
+ 'token' => cc.token,
508
+ 'last_4' => cc.last_4,
509
+ 'card_type' => cc.card_type,
510
+ 'masked_number' => cc.masked_number
394
511
  }
395
512
  end
396
513
  end
@@ -398,13 +515,16 @@ module ActiveMerchant #:nodoc:
398
515
  hash
399
516
  end
400
517
 
401
- def transaction_hash(transaction)
518
+ def transaction_hash(result)
519
+ return { 'processor_response_code' => response_code_from_result(result) } unless result.success?
520
+
521
+ transaction = result.transaction
402
522
  if transaction.vault_customer
403
523
  vault_customer = {
404
524
  }
405
- vault_customer["credit_cards"] = transaction.vault_customer.credit_cards.map do |cc|
525
+ vault_customer['credit_cards'] = transaction.vault_customer.credit_cards.map do |cc|
406
526
  {
407
- "bin" => cc.bin
527
+ 'bin' => cc.bin
408
528
  }
409
529
  end
410
530
  else
@@ -412,103 +532,372 @@ module ActiveMerchant #:nodoc:
412
532
  end
413
533
 
414
534
  customer_details = {
415
- "id" => transaction.customer_details.id,
416
- "email" => transaction.customer_details.email
535
+ 'id' => transaction.customer_details.id,
536
+ 'email' => transaction.customer_details.email,
537
+ 'phone' => transaction.customer_details.phone
417
538
  }
418
539
 
419
540
  billing_details = {
420
- "street_address" => transaction.billing_details.street_address,
421
- "extended_address" => transaction.billing_details.extended_address,
422
- "company" => transaction.billing_details.company,
423
- "locality" => transaction.billing_details.locality,
424
- "region" => transaction.billing_details.region,
425
- "postal_code" => transaction.billing_details.postal_code,
426
- "country_name" => transaction.billing_details.country_name,
541
+ 'street_address' => transaction.billing_details.street_address,
542
+ 'extended_address' => transaction.billing_details.extended_address,
543
+ 'company' => transaction.billing_details.company,
544
+ 'locality' => transaction.billing_details.locality,
545
+ 'region' => transaction.billing_details.region,
546
+ 'postal_code' => transaction.billing_details.postal_code,
547
+ 'country_name' => transaction.billing_details.country_name
427
548
  }
428
549
 
429
550
  shipping_details = {
430
- "street_address" => transaction.shipping_details.street_address,
431
- "extended_address" => transaction.shipping_details.extended_address,
432
- "company" => transaction.shipping_details.company,
433
- "locality" => transaction.shipping_details.locality,
434
- "region" => transaction.shipping_details.region,
435
- "postal_code" => transaction.shipping_details.postal_code,
436
- "country_name" => transaction.shipping_details.country_name,
551
+ 'street_address' => transaction.shipping_details.street_address,
552
+ 'extended_address' => transaction.shipping_details.extended_address,
553
+ 'company' => transaction.shipping_details.company,
554
+ 'locality' => transaction.shipping_details.locality,
555
+ 'region' => transaction.shipping_details.region,
556
+ 'postal_code' => transaction.shipping_details.postal_code,
557
+ 'country_name' => transaction.shipping_details.country_name
437
558
  }
438
559
  credit_card_details = {
439
- "masked_number" => transaction.credit_card_details.masked_number,
440
- "bin" => transaction.credit_card_details.bin,
441
- "last_4" => transaction.credit_card_details.last_4,
442
- "card_type" => transaction.credit_card_details.card_type,
443
- "token" => transaction.credit_card_details.token
560
+ 'masked_number' => transaction.credit_card_details.masked_number,
561
+ 'bin' => transaction.credit_card_details.bin,
562
+ 'last_4' => transaction.credit_card_details.last_4,
563
+ 'card_type' => transaction.credit_card_details.card_type,
564
+ 'token' => transaction.credit_card_details.token
444
565
  }
445
566
 
567
+ if transaction.risk_data
568
+ risk_data = {
569
+ 'id' => transaction.risk_data.id,
570
+ 'decision' => transaction.risk_data.decision,
571
+ 'device_data_captured' => transaction.risk_data.device_data_captured,
572
+ 'fraud_service_provider' => transaction.risk_data.fraud_service_provider
573
+ }
574
+ else
575
+ risk_data = nil
576
+ end
577
+
446
578
  {
447
- "order_id" => transaction.order_id,
448
- "status" => transaction.status,
449
- "credit_card_details" => credit_card_details,
450
- "customer_details" => customer_details,
451
- "billing_details" => billing_details,
452
- "shipping_details" => shipping_details,
453
- "vault_customer" => vault_customer,
454
- "merchant_account_id" => transaction.merchant_account_id
579
+ 'order_id' => transaction.order_id,
580
+ 'amount' => transaction.amount.to_s,
581
+ 'status' => transaction.status,
582
+ 'credit_card_details' => credit_card_details,
583
+ 'customer_details' => customer_details,
584
+ 'billing_details' => billing_details,
585
+ 'shipping_details' => shipping_details,
586
+ 'vault_customer' => vault_customer,
587
+ 'merchant_account_id' => transaction.merchant_account_id,
588
+ 'risk_data' => risk_data,
589
+ 'network_transaction_id' => transaction.network_transaction_id || nil,
590
+ 'processor_response_code' => response_code_from_result(result),
591
+ 'recurring' => transaction.recurring
455
592
  }
456
593
  end
457
594
 
458
595
  def create_transaction_parameters(money, credit_card_or_vault_id, options)
459
596
  parameters = {
460
- :amount => amount(money).to_s,
461
- :order_id => options[:order_id],
462
- :customer => {
463
- :id => options[:store] == true ? "" : options[:store],
464
- :email => scrub_email(options[:email])
597
+ amount: localized_amount(money, options[:currency] || default_currency).to_s,
598
+ order_id: options[:order_id],
599
+ customer: {
600
+ id: options[:store] == true ? '' : options[:store],
601
+ email: scrub_email(options[:email]),
602
+ phone: options[:phone] || (options[:billing_address][:phone] if options[:billing_address] &&
603
+ options[:billing_address][:phone])
465
604
  },
466
- :options => {
467
- :store_in_vault => options[:store] ? true : false,
468
- :submit_for_settlement => options[:submit_for_settlement]
605
+ options: {
606
+ store_in_vault: options[:store] ? true : false,
607
+ submit_for_settlement: options[:submit_for_settlement],
608
+ hold_in_escrow: options[:hold_in_escrow]
469
609
  }
470
610
  }
471
611
 
472
612
  parameters[:custom_fields] = options[:custom_fields]
473
613
  parameters[:device_data] = options[:device_data] if options[:device_data]
474
- if merchant_account_id = (options[:merchant_account_id] || @merchant_account_id)
475
- parameters[:merchant_account_id] = merchant_account_id
614
+ parameters[:service_fee_amount] = options[:service_fee_amount] if options[:service_fee_amount]
615
+
616
+ add_account_type(parameters, options) if options[:account_type]
617
+ add_skip_options(parameters, options)
618
+ add_merchant_account_id(parameters, options)
619
+
620
+ add_payment_method(parameters, credit_card_or_vault_id, options)
621
+ add_stored_credential_data(parameters, credit_card_or_vault_id, options)
622
+ add_addresses(parameters, options)
623
+
624
+ add_descriptor(parameters, options)
625
+ add_risk_data(parameters, options)
626
+ add_travel_data(parameters, options) if options[:travel_data]
627
+ add_lodging_data(parameters, options) if options[:lodging_data]
628
+ add_channel(parameters, options)
629
+ add_transaction_source(parameters, options)
630
+
631
+ add_level_2_data(parameters, options)
632
+ add_level_3_data(parameters, options)
633
+
634
+ add_3ds_info(parameters, options[:three_d_secure])
635
+
636
+ if options[:payment_method_nonce].is_a?(String)
637
+ parameters.delete(:customer)
638
+ parameters[:payment_method_nonce] = options[:payment_method_nonce]
639
+ end
640
+
641
+ parameters
642
+ end
643
+
644
+ def add_account_type(parameters, options)
645
+ parameters[:options][:credit_card] = {}
646
+ parameters[:options][:credit_card][:account_type] = options[:account_type]
647
+ end
648
+
649
+ def add_skip_options(parameters, options)
650
+ parameters[:options][:skip_advanced_fraud_checking] = options[:skip_advanced_fraud_checking] if options[:skip_advanced_fraud_checking]
651
+ parameters[:options][:skip_avs] = options[:skip_avs] if options[:skip_avs]
652
+ parameters[:options][:skip_cvv] = options[:skip_cvv] if options[:skip_cvv]
653
+ end
654
+
655
+ def add_merchant_account_id(parameters, options)
656
+ return unless merchant_account_id = (options[:merchant_account_id] || @merchant_account_id)
657
+
658
+ parameters[:merchant_account_id] = merchant_account_id
659
+ end
660
+
661
+ def add_transaction_source(parameters, options)
662
+ parameters[:transaction_source] = options[:transaction_source] if options[:transaction_source]
663
+ parameters[:transaction_source] = 'recurring' if options[:recurring]
664
+ end
665
+
666
+ def add_addresses(parameters, options)
667
+ parameters[:billing] = map_address(options[:billing_address]) if options[:billing_address]
668
+ parameters[:shipping] = map_address(options[:shipping_address]) if options[:shipping_address]
669
+ end
670
+
671
+ def add_channel(parameters, options)
672
+ channel = @options[:channel] || application_id
673
+ parameters[:channel] = channel if channel
674
+ end
675
+
676
+ def add_descriptor(parameters, options)
677
+ return unless options[:descriptor_name] || options[:descriptor_phone] || options[:descriptor_url]
678
+
679
+ parameters[:descriptor] = {
680
+ name: options[:descriptor_name],
681
+ phone: options[:descriptor_phone],
682
+ url: options[:descriptor_url]
683
+ }
684
+ end
685
+
686
+ def add_risk_data(parameters, options)
687
+ return unless options[:risk_data]
688
+
689
+ parameters[:risk_data] = {
690
+ customer_browser: options[:risk_data][:customer_browser],
691
+ customer_ip: options[:risk_data][:customer_ip]
692
+ }
693
+ end
694
+
695
+ def add_level_2_data(parameters, options)
696
+ parameters[:tax_amount] = options[:tax_amount] if options[:tax_amount]
697
+ parameters[:tax_exempt] = options[:tax_exempt] if options[:tax_exempt]
698
+ parameters[:purchase_order_number] = options[:purchase_order_number] if options[:purchase_order_number]
699
+ end
700
+
701
+ def add_level_3_data(parameters, options)
702
+ parameters[:shipping_amount] = options[:shipping_amount] if options[:shipping_amount]
703
+ parameters[:discount_amount] = options[:discount_amount] if options[:discount_amount]
704
+ parameters[:ships_from_postal_code] = options[:ships_from_postal_code] if options[:ships_from_postal_code]
705
+
706
+ parameters[:line_items] = options[:line_items] if options[:line_items]
707
+ end
708
+
709
+ def add_travel_data(parameters, options)
710
+ parameters[:industry] = {
711
+ industry_type: Braintree::Transaction::IndustryType::TravelAndCruise,
712
+ data: {}
713
+ }
714
+
715
+ parameters[:industry][:data][:travel_package] = options[:travel_data][:travel_package] if options[:travel_data][:travel_package]
716
+ parameters[:industry][:data][:departure_date] = options[:travel_data][:departure_date] if options[:travel_data][:departure_date]
717
+ parameters[:industry][:data][:lodging_check_in_date] = options[:travel_data][:lodging_check_in_date] if options[:travel_data][:lodging_check_in_date]
718
+ parameters[:industry][:data][:lodging_check_out_date] = options[:travel_data][:lodging_check_out_date] if options[:travel_data][:lodging_check_out_date]
719
+ parameters[:industry][:data][:lodging_name] = options[:travel_data][:lodging_name] if options[:travel_data][:lodging_name]
720
+ end
721
+
722
+ def add_lodging_data(parameters, options)
723
+ parameters[:industry] = {
724
+ industry_type: Braintree::Transaction::IndustryType::Lodging,
725
+ data: {}
726
+ }
727
+
728
+ parameters[:industry][:data][:folio_number] = options[:lodging_data][:folio_number] if options[:lodging_data][:folio_number]
729
+ parameters[:industry][:data][:check_in_date] = options[:lodging_data][:check_in_date] if options[:lodging_data][:check_in_date]
730
+ parameters[:industry][:data][:check_out_date] = options[:lodging_data][:check_out_date] if options[:lodging_data][:check_out_date]
731
+ parameters[:industry][:data][:room_rate] = options[:lodging_data][:room_rate] if options[:lodging_data][:room_rate]
732
+ end
733
+
734
+ def add_3ds_info(parameters, three_d_secure_opts)
735
+ return if empty?(three_d_secure_opts)
736
+
737
+ pass_thru = {}
738
+
739
+ pass_thru[:three_d_secure_version] = three_d_secure_opts[:version] if three_d_secure_opts[:version]
740
+ pass_thru[:eci_flag] = three_d_secure_opts[:eci] if three_d_secure_opts[:eci]
741
+ pass_thru[:cavv_algorithm] = three_d_secure_opts[:cavv_algorithm] if three_d_secure_opts[:cavv_algorithm]
742
+ pass_thru[:cavv] = three_d_secure_opts[:cavv] if three_d_secure_opts[:cavv]
743
+ pass_thru[:directory_response] = three_d_secure_opts[:directory_response_status] if three_d_secure_opts[:directory_response_status]
744
+ pass_thru[:authentication_response] = three_d_secure_opts[:authentication_response_status] if three_d_secure_opts[:authentication_response_status]
745
+
746
+ parameters[:three_d_secure_pass_thru] = pass_thru.merge(xid_or_ds_trans_id(three_d_secure_opts))
747
+ end
748
+
749
+ def xid_or_ds_trans_id(three_d_secure_opts)
750
+ if three_d_secure_opts[:version].to_f >= 2
751
+ { ds_transaction_id: three_d_secure_opts[:ds_transaction_id] }
752
+ else
753
+ { xid: three_d_secure_opts[:xid] }
476
754
  end
755
+ end
756
+
757
+ def add_stored_credential_data(parameters, credit_card_or_vault_id, options)
758
+ return unless (stored_credential = options[:stored_credential])
477
759
 
478
- if options[:recurring]
479
- parameters[:recurring] = true
760
+ parameters[:external_vault] = {}
761
+ if stored_credential[:initial_transaction]
762
+ parameters[:external_vault][:status] = 'will_vault'
763
+ else
764
+ parameters[:external_vault][:status] = 'vaulted'
765
+ parameters[:external_vault][:previous_network_transaction_id] = stored_credential[:network_transaction_id]
766
+ end
767
+ if stored_credential[:initiator] == 'merchant'
768
+ if stored_credential[:reason_type] == 'installment'
769
+ parameters[:transaction_source] = 'recurring'
770
+ else
771
+ parameters[:transaction_source] = stored_credential[:reason_type]
772
+ end
773
+ elsif %w(recurring_first moto).include?(stored_credential[:reason_type])
774
+ parameters[:transaction_source] = stored_credential[:reason_type]
775
+ else
776
+ parameters[:transaction_source] = ''
480
777
  end
778
+ end
481
779
 
780
+ def add_payment_method(parameters, credit_card_or_vault_id, options)
482
781
  if credit_card_or_vault_id.is_a?(String) || credit_card_or_vault_id.is_a?(Integer)
483
782
  if options[:payment_method_token]
484
783
  parameters[:payment_method_token] = credit_card_or_vault_id
784
+ options.delete(:billing_address)
785
+ elsif options[:payment_method_nonce]
786
+ parameters[:payment_method_nonce] = credit_card_or_vault_id
485
787
  else
486
788
  parameters[:customer_id] = credit_card_or_vault_id
487
789
  end
488
790
  else
489
791
  parameters[:customer].merge!(
490
- :first_name => credit_card_or_vault_id.first_name,
491
- :last_name => credit_card_or_vault_id.last_name
792
+ first_name: credit_card_or_vault_id.first_name,
793
+ last_name: credit_card_or_vault_id.last_name
492
794
  )
493
- parameters[:credit_card] = {
494
- :number => credit_card_or_vault_id.number,
495
- :cvv => credit_card_or_vault_id.verification_value,
496
- :expiration_month => credit_card_or_vault_id.month.to_s.rjust(2, "0"),
497
- :expiration_year => credit_card_or_vault_id.year.to_s
498
- }
795
+ if credit_card_or_vault_id.is_a?(NetworkTokenizationCreditCard)
796
+ if credit_card_or_vault_id.source == :apple_pay
797
+ parameters[:apple_pay_card] = {
798
+ number: credit_card_or_vault_id.number,
799
+ expiration_month: credit_card_or_vault_id.month.to_s.rjust(2, '0'),
800
+ expiration_year: credit_card_or_vault_id.year.to_s,
801
+ cardholder_name: credit_card_or_vault_id.name,
802
+ cryptogram: credit_card_or_vault_id.payment_cryptogram,
803
+ eci_indicator: credit_card_or_vault_id.eci
804
+ }
805
+ elsif credit_card_or_vault_id.source == :android_pay || credit_card_or_vault_id.source == :google_pay
806
+ Braintree::Version::Major < 3 ? pay_card = :android_pay_card : pay_card = :google_pay_card
807
+ parameters[pay_card] = {
808
+ number: credit_card_or_vault_id.number,
809
+ cryptogram: credit_card_or_vault_id.payment_cryptogram,
810
+ expiration_month: credit_card_or_vault_id.month.to_s.rjust(2, '0'),
811
+ expiration_year: credit_card_or_vault_id.year.to_s,
812
+ google_transaction_id: credit_card_or_vault_id.transaction_id,
813
+ source_card_type: credit_card_or_vault_id.brand,
814
+ source_card_last_four: credit_card_or_vault_id.last_digits,
815
+ eci_indicator: credit_card_or_vault_id.eci
816
+ }
817
+ end
818
+ else
819
+ parameters[:credit_card] = {
820
+ number: credit_card_or_vault_id.number,
821
+ cvv: credit_card_or_vault_id.verification_value,
822
+ expiration_month: credit_card_or_vault_id.month.to_s.rjust(2, '0'),
823
+ expiration_year: credit_card_or_vault_id.year.to_s,
824
+ cardholder_name: credit_card_or_vault_id.name
825
+ }
826
+ end
499
827
  end
500
- parameters[:billing] = map_address(options[:billing_address]) if options[:billing_address] && !options[:payment_method_token]
501
- parameters[:shipping] = map_address(options[:shipping_address]) if options[:shipping_address]
502
- parameters[:channel] = application_id if application_id.present? && application_id != "ActiveMerchant"
828
+ end
503
829
 
504
- if options[:descriptor_name] || options[:descriptor_phone]
505
- parameters[:descriptor] = {
506
- name: options[:descriptor_name],
507
- phone: options[:descriptor_phone]
508
- }
830
+ def bank_account_errors(payment_method, options)
831
+ if payment_method.validate.present?
832
+ payment_method.validate
833
+ elsif options[:billing_address].blank?
834
+ 'billing_address is required parameter to store and verify Bank accounts.'
835
+ elsif options[:ach_mandate].blank?
836
+ 'ach_mandate is a required parameter to process bank acccount transactions see (https://developer.paypal.com/braintree/docs/guides/ach/client-side#show-required-authorization-language)'
509
837
  end
838
+ end
510
839
 
511
- parameters
840
+ def add_bank_account_to_customer(payment_method, options)
841
+ bank_account_nonce, error_message = TokenNonce.new(@braintree_gateway, options).create_token_nonce_for_payment_method payment_method
842
+ return Response.new(false, error_message) unless bank_account_nonce.present?
843
+
844
+ result = @braintree_gateway.payment_method.create(
845
+ customer_id: options[:customer],
846
+ payment_method_nonce: bank_account_nonce,
847
+ options: {
848
+ us_bank_account_verification_method: 'network_check'
849
+ }
850
+ )
851
+
852
+ verified = result.success? && result.payment_method&.verified
853
+ message = message_from_result(result)
854
+ message = not_verified_reason(result.payment_method) unless verified
855
+
856
+ Response.new(verified, message,
857
+ {
858
+ customer_vault_id: options[:customer],
859
+ bank_account_token: result.payment_method&.token,
860
+ verified: verified
861
+ },
862
+ authorization: result.payment_method&.token)
863
+ end
864
+
865
+ def not_verified_reason(bank_account)
866
+ return unless bank_account.verifications.present?
867
+
868
+ verification = bank_account.verifications.first
869
+ "verification_status: [#{verification.status}], processor_response: [#{verification.processor_response_code}-#{verification.processor_response_text}]"
870
+ end
871
+
872
+ def store_bank_account(payment_method, options, multi_response)
873
+ multi_response.process { create_customer_from_bank_account payment_method, options } unless multi_response.params['exists']
874
+ multi_response.process { add_bank_account_to_customer payment_method, options }
875
+ end
876
+
877
+ def store_credit_card(payment_method, options, multi_response)
878
+ process_by = multi_response.params['exists'] ? :add_credit_card_to_customer : :add_customer_with_credit_card
879
+ multi_response.process { send process_by, payment_method, options }
880
+ end
881
+
882
+ def create_customer_from_bank_account(payment_method, options)
883
+ parameters = {
884
+ id: options[:customer],
885
+ first_name: payment_method.first_name,
886
+ last_name: payment_method.last_name,
887
+ email: scrub_email(options[:email]),
888
+ phone: options[:phone] || options.dig(:billing_address, :phone),
889
+ device_data: options[:device_data]
890
+ }.compact
891
+
892
+ result = @braintree_gateway.customer.create(parameters)
893
+ customer_id = result.customer.id if result.success?
894
+ options[:customer] = customer_id
895
+
896
+ Response.new(
897
+ result.success?,
898
+ message_from_result(result),
899
+ { customer_vault_id: customer_id, 'exists': true }
900
+ )
512
901
  end
513
902
  end
514
903
  end