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,208 +1,714 @@
1
1
  module ActiveMerchant #:nodoc:
2
2
  module Billing #:nodoc:
3
3
  class AdyenGateway < Gateway
4
- self.test_url = 'https://pal-test.adyen.com/pal/adapter/httppost'
5
- self.live_url = 'https://pal-live.adyen.com/pal/adapter/httppost'
4
+ # we recommend setting up merchant-specific endpoints.
5
+ # https://docs.adyen.com/developers/api-manual#apiendpoints
6
+ self.test_url = 'https://pal-test.adyen.com/pal/servlet/'
7
+ self.live_url = 'https://pal-live.adyen.com/pal/servlet/'
8
+
9
+ self.supported_countries = %w(AT AU BE BG BR CH CY CZ DE DK EE ES FI FR GB GI GR HK HU IE IS IT LI LT LU LV MC MT MX NL NO PL PT RO SE SG SK SI US)
10
+ self.default_currency = 'USD'
11
+ self.currencies_without_fractions = %w(CVE DJF GNF IDR JPY KMF KRW PYG RWF UGX VND VUV XAF XOF XPF)
12
+ self.currencies_with_three_decimal_places = %w(BHD IQD JOD KWD LYD OMR TND)
13
+ self.supported_cardtypes = %i[visa master american_express diners_club jcb dankort maestro discover elo naranja cabal unionpay]
6
14
 
7
- self.supported_countries = ['AR', 'AT', 'BE', 'BR', 'CA', 'CH', 'CL', 'CN', 'CO', 'DE', 'DK', 'EE', 'ES', 'FI', 'FR', 'GB', 'HK', 'ID', 'IE', 'IL', 'IN', 'IT', 'JP', 'KR', 'LU', 'MX', 'MY', 'NL', 'NO', 'PA', 'PE', 'PH', 'PL', 'PT', 'RU', 'SE', 'SG', 'TH', 'TR', 'TW', 'US', 'VN', 'ZA']
8
- self.default_currency = 'EUR'
9
15
  self.money_format = :cents
10
- self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb, :dankort, :maestro]
11
16
 
12
17
  self.homepage_url = 'https://www.adyen.com/'
13
18
  self.display_name = 'Adyen'
14
19
 
20
+ PAYMENT_API_VERSION = 'v64'
21
+ RECURRING_API_VERSION = 'v49'
22
+
23
+ STANDARD_ERROR_CODE_MAPPING = {
24
+ '101' => STANDARD_ERROR_CODE[:incorrect_number],
25
+ '103' => STANDARD_ERROR_CODE[:invalid_cvc],
26
+ '131' => STANDARD_ERROR_CODE[:incorrect_address],
27
+ '132' => STANDARD_ERROR_CODE[:incorrect_address],
28
+ '133' => STANDARD_ERROR_CODE[:incorrect_address],
29
+ '134' => STANDARD_ERROR_CODE[:incorrect_address],
30
+ '135' => STANDARD_ERROR_CODE[:incorrect_address]
31
+ }
32
+
15
33
  def initialize(options = {})
16
- requires!(options, :company, :merchant, :password)
34
+ requires!(options, :username, :password, :merchant_account)
35
+ @username, @password, @merchant_account = options.values_at(:username, :password, :merchant_account)
17
36
  super
18
37
  end
19
38
 
20
- def purchase(money, creditcard, options = {})
39
+ def purchase(money, payment, options = {})
40
+ if options[:execute_threed] || options[:threed_dynamic]
41
+ authorize(money, payment, options)
42
+ else
43
+ MultiResponse.run do |r|
44
+ r.process { authorize(money, payment, options) }
45
+ r.process { capture(money, r.authorization, capture_options(options)) }
46
+ end
47
+ end
48
+ end
49
+
50
+ def authorize(money, payment, options = {})
21
51
  requires!(options, :order_id)
52
+ post = init_post(options)
53
+ add_invoice(post, money, options)
54
+ add_payment(post, payment, options)
55
+ add_extra_data(post, payment, options)
56
+ add_stored_credentials(post, payment, options)
57
+ add_address(post, options)
58
+ add_installments(post, options) if options[:installments]
59
+ add_3ds(post, options)
60
+ add_3ds_authenticated_data(post, options)
61
+ add_splits(post, options)
62
+ add_recurring_contract(post, options)
63
+ add_network_transaction_reference(post, options)
64
+ add_application_info(post, options)
65
+ commit('authorise', post, options)
66
+ end
22
67
 
23
- MultiResponse.run do |r|
24
- r.process { authorize(money, creditcard, options) }
25
- r.process { capture(money, r.authorization, options) }
26
- end
68
+ def capture(money, authorization, options = {})
69
+ post = init_post(options)
70
+ add_invoice_for_modification(post, money, options)
71
+ add_reference(post, authorization, options)
72
+ add_splits(post, options)
73
+ add_network_transaction_reference(post, options)
74
+ commit('capture', post, options)
27
75
  end
28
76
 
29
- def authorize(money, creditcard, options = {})
77
+ def refund(money, authorization, options = {})
78
+ post = init_post(options)
79
+ add_invoice_for_modification(post, money, options)
80
+ add_reference(post, authorization, options)
81
+ add_splits(post, options)
82
+ add_network_transaction_reference(post, options)
83
+ commit('refund', post, options)
84
+ end
85
+
86
+ def credit(money, payment, options = {})
87
+ action = 'refundWithData'
88
+ post = init_post(options)
89
+ add_invoice(post, money, options)
90
+ add_payment(post, payment, options, action)
91
+ add_shopper_reference(post, options)
92
+ add_network_transaction_reference(post, options)
93
+ commit(action, post, options)
94
+ end
95
+
96
+ def void(authorization, options = {})
97
+ post = init_post(options)
98
+ endpoint = options[:cancel_or_refund] ? 'cancelOrRefund' : 'cancel'
99
+ add_reference(post, authorization, options)
100
+ add_network_transaction_reference(post, options)
101
+ commit(endpoint, post, options)
102
+ end
103
+
104
+ def adjust(money, authorization, options = {})
105
+ post = init_post(options)
106
+ add_invoice_for_modification(post, money, options)
107
+ add_reference(post, authorization, options)
108
+ add_extra_data(post, nil, options)
109
+ commit('adjustAuthorisation', post, options)
110
+ end
111
+
112
+ def store(credit_card, options = {})
30
113
  requires!(options, :order_id)
114
+ post = init_post(options)
115
+ add_invoice(post, 0, options)
116
+ add_payment(post, credit_card, options)
117
+ add_extra_data(post, credit_card, options)
118
+ add_stored_credentials(post, credit_card, options)
119
+ add_address(post, options)
31
120
 
32
- post = {}
33
- post[:paymentRequest] = payment_request(money, options)
34
- post[:paymentRequest][:amount] = amount_hash(money, options[:currency])
35
- post[:paymentRequest][:card] = credit_card_hash(creditcard)
121
+ options[:recurring_contract_type] ||= 'RECURRING'
122
+ add_recurring_contract(post, options)
36
123
 
37
- if address = (options[:billing_address] || options[:address])
38
- post[:paymentRequest][:billingAddress] = address_hash(address)
124
+ action = options[:tokenize_only] ? 'storeToken' : 'authorise'
125
+
126
+ initial_response = commit(action, post, options)
127
+
128
+ if initial_response.success? && card_not_stored?(initial_response)
129
+ unsupported_failure_response(initial_response)
130
+ else
131
+ initial_response
39
132
  end
133
+ end
134
+
135
+ def unstore(options = {})
136
+ requires!(options, :shopper_reference, :recurring_detail_reference)
137
+ post = {}
40
138
 
41
- if options[:shipping_address]
42
- post[:paymentRequest][:deliveryAddress] = address_hash(options[:shipping_address])
139
+ add_shopper_reference(post, options)
140
+ add_merchant_account(post, options)
141
+ post[:recurringDetailReference] = options[:recurring_detail_reference]
142
+
143
+ commit('disable', post, options)
144
+ end
145
+
146
+ def verify(credit_card, options = {})
147
+ amount = options[:verify_amount]&.to_i || 0
148
+ MultiResponse.run(:use_first_response) do |r|
149
+ r.process { authorize(amount, credit_card, options) }
150
+ options[:idempotency_key] = nil
151
+ r.process(:ignore_result) { void(r.authorization, options) }
43
152
  end
153
+ end
44
154
 
45
- commit('Payment.authorise', post)
155
+ def supports_scrubbing?
156
+ true
46
157
  end
47
158
 
48
- def capture(money, authorization, options = {})
49
- requires!(options, :order_id)
159
+ def supports_network_tokenization?
160
+ true
161
+ end
50
162
 
51
- post = {}
52
- post[:modificationRequest] = modification_request(authorization, options)
53
- post[:modificationRequest][:modificationAmount] = amount_hash(money, options[:currency])
163
+ def scrub(transcript)
164
+ transcript.
165
+ gsub(%r((Authorization: Basic )\w+), '\1[FILTERED]').
166
+ gsub(%r(("number\\?"\s*:\s*\\?")[^"]*)i, '\1[FILTERED]').
167
+ gsub(%r(("cvc\\?"\s*:\s*\\?")[^"]*)i, '\1[FILTERED]').
168
+ gsub(%r(("cavv\\?"\s*:\s*\\?")[^"]*)i, '\1[FILTERED]').
169
+ gsub(%r(("bankLocationId\\?"\s*:\s*\\?")[^"]*)i, '\1[FILTERED]').
170
+ gsub(%r(("iban\\?"\s*:\s*\\?")[^"]*)i, '\1[FILTERED]').
171
+ gsub(%r(("bankAccountNumber\\?"\s*:\s*\\?")[^"]*)i, '\1[FILTERED]')
172
+ end
54
173
 
55
- commit('Payment.capture', post)
174
+ private
175
+
176
+ AVS_MAPPING = {
177
+ '0' => 'R', # Unknown
178
+ '1' => 'A', # Address matches, postal code doesn't
179
+ '2' => 'N', # Neither postal code nor address match
180
+ '3' => 'R', # AVS unavailable
181
+ '4' => 'E', # AVS not supported for this card type
182
+ '5' => 'U', # No AVS data provided
183
+ '6' => 'Z', # Postal code matches, address doesn't match
184
+ '7' => 'D', # Both postal code and address match
185
+ '8' => 'U', # Address not checked, postal code unknown
186
+ '9' => 'B', # Address matches, postal code unknown
187
+ '10' => 'N', # Address doesn't match, postal code unknown
188
+ '11' => 'U', # Postal code not checked, address unknown
189
+ '12' => 'B', # Address matches, postal code not checked
190
+ '13' => 'U', # Address doesn't match, postal code not checked
191
+ '14' => 'P', # Postal code matches, address unknown
192
+ '15' => 'P', # Postal code matches, address not checked
193
+ '16' => 'N', # Postal code doesn't match, address unknown
194
+ '17' => 'U', # Postal code doesn't match, address not checked
195
+ '18' => 'I', # Neither postal code nor address were checked
196
+ '19' => 'L', # Name and postal code matches.
197
+ '20' => 'V', # Name, address and postal code matches.
198
+ '21' => 'O', # Name and address matches.
199
+ '22' => 'K', # Name matches.
200
+ '23' => 'F', # Postal code matches, name doesn't match.
201
+ '24' => 'H', # Both postal code and address matches, name doesn't match.
202
+ '25' => 'T', # Address matches, name doesn't match.
203
+ '26' => 'N' # Neither postal code, address nor name matches.
204
+ }
205
+
206
+ CVC_MAPPING = {
207
+ '0' => 'P', # Unknown
208
+ '1' => 'M', # Matches
209
+ '2' => 'N', # Does not match
210
+ '3' => 'P', # Not checked
211
+ '4' => 'S', # No CVC/CVV provided, but was required
212
+ '5' => 'U', # Issuer not certifed by CVC/CVV
213
+ '6' => 'P' # No CVC/CVV provided
214
+ }
215
+
216
+ NETWORK_TOKENIZATION_CARD_SOURCE = {
217
+ 'apple_pay' => 'applepay',
218
+ 'android_pay' => 'androidpay',
219
+ 'google_pay' => 'paywithgoogle'
220
+ }
221
+
222
+ def add_extra_data(post, payment, options)
223
+ post[:telephoneNumber] = (options[:billing_address][:phone_number] if options.dig(:billing_address, :phone_number)) || (options[:billing_address][:phone] if options.dig(:billing_address, :phone)) || ''
224
+ post[:fraudOffset] = options[:fraud_offset] if options[:fraud_offset]
225
+ post[:selectedBrand] = options[:selected_brand] if options[:selected_brand]
226
+ post[:selectedBrand] ||= NETWORK_TOKENIZATION_CARD_SOURCE[payment.source.to_s] if payment.is_a?(NetworkTokenizationCreditCard)
227
+ post[:deliveryDate] = options[:delivery_date] if options[:delivery_date]
228
+ post[:merchantOrderReference] = options[:merchant_order_reference] if options[:merchant_order_reference]
229
+ post[:captureDelayHours] = options[:capture_delay_hours] if options[:capture_delay_hours]
230
+ post[:additionalData] ||= {}
231
+ post[:additionalData][:overwriteBrand] = normalize(options[:overwrite_brand]) if options[:overwrite_brand]
232
+ post[:additionalData][:customRoutingFlag] = options[:custom_routing_flag] if options[:custom_routing_flag]
233
+ post[:additionalData]['paymentdatasource.type'] = NETWORK_TOKENIZATION_CARD_SOURCE[payment.source.to_s] if payment.is_a?(NetworkTokenizationCreditCard)
234
+ post[:additionalData][:authorisationType] = options[:authorisation_type] if options[:authorisation_type]
235
+ post[:additionalData][:adjustAuthorisationData] = options[:adjust_authorisation_data] if options[:adjust_authorisation_data]
236
+ post[:additionalData][:industryUsage] = options[:industry_usage] if options[:industry_usage]
237
+ post[:additionalData][:RequestedTestAcquirerResponseCode] = options[:requested_test_acquirer_response_code] if options[:requested_test_acquirer_response_code] && test?
238
+ post[:deviceFingerprint] = options[:device_fingerprint] if options[:device_fingerprint]
239
+ add_shopper_data(post, options)
240
+ add_risk_data(post, options)
241
+ add_shopper_reference(post, options)
242
+ add_merchant_data(post, options)
56
243
  end
57
244
 
58
- def refund(money, authorization, options = {})
59
- requires!(options, :order_id)
245
+ def add_shopper_data(post, options)
246
+ post[:shopperEmail] = options[:email] if options[:email]
247
+ post[:shopperEmail] = options[:shopper_email] if options[:shopper_email]
248
+ post[:shopperIP] = options[:ip] if options[:ip]
249
+ post[:shopperIP] = options[:shopper_ip] if options[:shopper_ip]
250
+ post[:shopperStatement] = options[:shopper_statement] if options[:shopper_statement]
251
+ post[:additionalData][:updateShopperStatement] = options[:update_shopper_statement] if options[:update_shopper_statement]
252
+ end
60
253
 
61
- post = {}
62
- post[:modificationRequest] = modification_request(authorization, options)
63
- post[:modificationRequest][:modificationAmount] = amount_hash(money, options[:currency])
254
+ def add_merchant_data(post, options)
255
+ post[:additionalData][:subMerchantID] = options[:sub_merchant_id] if options[:sub_merchant_id]
256
+ post[:additionalData][:subMerchantName] = options[:sub_merchant_name] if options[:sub_merchant_name]
257
+ post[:additionalData][:subMerchantStreet] = options[:sub_merchant_street] if options[:sub_merchant_street]
258
+ post[:additionalData][:subMerchantCity] = options[:sub_merchant_city] if options[:sub_merchant_city]
259
+ post[:additionalData][:subMerchantState] = options[:sub_merchant_state] if options[:sub_merchant_state]
260
+ post[:additionalData][:subMerchantPostalCode] = options[:sub_merchant_postal_code] if options[:sub_merchant_postal_code]
261
+ post[:additionalData][:subMerchantCountry] = options[:sub_merchant_country] if options[:sub_merchant_country]
262
+ post[:additionalData][:subMerchantTaxId] = options[:sub_merchant_tax_id] if options[:sub_merchant_tax_id]
263
+ post[:additionalData][:subMerchantMCC] = options[:sub_merchant_mcc] if options[:sub_merchant_mcc]
264
+ post[:additionalData] = post[:additionalData].merge(options[:sub_merchant_data]) if options[:sub_merchant_data]
265
+ end
64
266
 
65
- commit('Payment.refund', post)
267
+ def add_risk_data(post, options)
268
+ if (risk_data = options[:risk_data])
269
+ risk_data = Hash[risk_data.map { |k, v| ["riskdata.#{k}", v] }]
270
+ post[:additionalData].merge!(risk_data)
271
+ end
66
272
  end
67
273
 
68
- def void(identification, options = {})
69
- requires!(options, :order_id)
274
+ def add_splits(post, options)
275
+ return unless split_data = options[:splits]
276
+
277
+ splits = []
278
+ split_data.each do |split|
279
+ amount = {
280
+ value: split['amount']['value']
281
+ }
282
+ amount[:currency] = split['amount']['currency'] if split['amount']['currency']
283
+
284
+ split_hash = {
285
+ amount: amount,
286
+ type: split['type'],
287
+ reference: split['reference']
288
+ }
289
+ split_hash['account'] = split['account'] if split['account']
290
+ splits.push(split_hash)
291
+ end
292
+ post[:splits] = splits
293
+ end
70
294
 
71
- post = {}
72
- post[:modificationRequest] = modification_request(identification, options)
295
+ def add_stored_credentials(post, payment, options)
296
+ add_shopper_interaction(post, payment, options)
297
+ add_recurring_processing_model(post, options)
298
+ end
73
299
 
74
- commit('Payment.cancel', post)
300
+ def add_merchant_account(post, options)
301
+ post[:merchantAccount] = options[:merchant_account] || @merchant_account
75
302
  end
76
303
 
77
- def verify(creditcard, options = {})
78
- authorize(0, creditcard, options)
304
+ def add_shopper_reference(post, options)
305
+ post[:shopperReference] = options[:shopper_reference] if options[:shopper_reference]
79
306
  end
80
307
 
81
- private
308
+ def add_shopper_interaction(post, payment, options = {})
309
+ if (options.dig(:stored_credential, :initial_transaction) && options.dig(:stored_credential, :initiator) == 'cardholder') ||
310
+ (payment.respond_to?(:verification_value) && payment.verification_value && options.dig(:stored_credential, :initial_transaction).nil?) ||
311
+ payment.is_a?(NetworkTokenizationCreditCard)
312
+ shopper_interaction = 'Ecommerce'
313
+ else
314
+ shopper_interaction = 'ContAuth'
315
+ end
82
316
 
83
- def commit(action, post)
84
- request = post_data(flatten_hash(post.merge(:action => action)))
85
- raw_response = ssl_post(url, request, headers)
86
- response = parse(raw_response)
317
+ post[:shopperInteraction] = options[:shopper_interaction] || shopper_interaction
318
+ end
87
319
 
88
- Response.new(
89
- success_from(response),
90
- message_from(response),
91
- response,
92
- test: test?,
93
- authorization: response['pspReference']
94
- )
320
+ def add_recurring_processing_model(post, options)
321
+ return unless options.dig(:stored_credential, :reason_type) || options[:recurring_processing_model]
95
322
 
96
- rescue ResponseError => e
97
- case e.response.code
98
- when '401'
99
- return Response.new(false, 'Invalid credentials', {}, :test => test?)
100
- when '500'
101
- if e.response.body.split(' ')[0] == 'validation'
102
- return Response.new(false, e.response.body.split(' ', 3)[2], {}, :test => test?)
323
+ if options.dig(:stored_credential, :reason_type) == 'unscheduled'
324
+ if options.dig(:stored_credential, :initiator) == 'merchant'
325
+ recurring_processing_model = 'UnscheduledCardOnFile'
326
+ else
327
+ recurring_processing_model = 'CardOnFile'
103
328
  end
329
+ else
330
+ recurring_processing_model = 'Subscription'
331
+ end
332
+
333
+ post[:recurringProcessingModel] = options[:recurring_processing_model] || recurring_processing_model
334
+ end
335
+
336
+ def add_address(post, options)
337
+ if address = options[:shipping_address]
338
+ post[:deliveryAddress] = {}
339
+ post[:deliveryAddress][:street] = address[:address1] || 'NA'
340
+ post[:deliveryAddress][:houseNumberOrName] = address[:address2] || 'NA'
341
+ post[:deliveryAddress][:postalCode] = address[:zip] if address[:zip]
342
+ post[:deliveryAddress][:city] = address[:city] || 'NA'
343
+ post[:deliveryAddress][:stateOrProvince] = get_state(address)
344
+ post[:deliveryAddress][:country] = address[:country] if address[:country]
345
+ end
346
+ return unless post[:bankAccount]&.kind_of?(Hash) || post[:card]&.kind_of?(Hash)
347
+
348
+ if (address = options[:billing_address] || options[:address]) && address[:country]
349
+ post[:billingAddress] = {}
350
+ post[:billingAddress][:street] = address[:address1] || 'NA'
351
+ post[:billingAddress][:houseNumberOrName] = address[:address2] || 'NA'
352
+ post[:billingAddress][:postalCode] = address[:zip] if address[:zip]
353
+ post[:billingAddress][:city] = address[:city] || 'NA'
354
+ post[:billingAddress][:stateOrProvince] = get_state(address)
355
+ post[:billingAddress][:country] = address[:country] if address[:country]
104
356
  end
105
- raise
106
357
  end
107
358
 
108
- def flatten_hash(hash, prefix = nil)
109
- flat_hash = {}
110
- hash.each_pair do |key, val|
111
- conc_key = prefix.nil? ? key : "#{prefix}.#{key}"
112
- if val.is_a?(Hash)
113
- flat_hash.merge!(flatten_hash(val, conc_key))
359
+ def get_state(address)
360
+ address[:state] && !address[:state].blank? ? address[:state] : 'NA'
361
+ end
362
+
363
+ def add_invoice(post, money, options)
364
+ currency = options[:currency] || currency(money)
365
+ amount = {
366
+ value: localized_amount(money, currency),
367
+ currency: currency
368
+ }
369
+
370
+ post[:amount] = amount
371
+ end
372
+
373
+ def add_invoice_for_modification(post, money, options)
374
+ currency = options[:currency] || currency(money)
375
+ amount = {
376
+ value: localized_amount(money, currency),
377
+ currency: currency
378
+ }
379
+ post[:modificationAmount] = amount
380
+ end
381
+
382
+ def add_payment(post, payment, options, action = nil)
383
+ if payment.is_a?(String)
384
+ _, _, recurring_detail_reference = payment.split('#')
385
+ post[:selectedRecurringDetailReference] = recurring_detail_reference
386
+ options[:recurring_contract_type] ||= 'RECURRING'
387
+ elsif payment.is_a?(Check)
388
+ add_bank_account(post, payment, options, action)
389
+ else
390
+ add_mpi_data_for_network_tokenization_card(post, payment) if payment.is_a?(NetworkTokenizationCreditCard)
391
+ add_card(post, payment)
392
+ end
393
+ end
394
+
395
+ def add_bank_account(post, bank_account, options, action)
396
+ bank = {
397
+ bankAccountNumber: bank_account.account_number,
398
+ ownerName: bank_account.name,
399
+ countryCode: options[:billing_address][:country]
400
+ }
401
+
402
+ action == 'refundWithData' ? bank[:iban] = bank_account.routing_number : bank[:bankLocationId] = bank_account.routing_number
403
+
404
+ requires!(bank, :bankAccountNumber, :ownerName, :countryCode)
405
+ post[:bankAccount] = bank
406
+ end
407
+
408
+ def add_card(post, credit_card)
409
+ card = {
410
+ expiryMonth: credit_card.month,
411
+ expiryYear: credit_card.year,
412
+ holderName: credit_card.name,
413
+ number: credit_card.number,
414
+ cvc: credit_card.verification_value
415
+ }
416
+
417
+ card.delete_if { |_k, v| v.blank? }
418
+ card[:holderName] ||= 'Not Provided'
419
+ requires!(card, :expiryMonth, :expiryYear, :holderName, :number)
420
+ post[:card] = card
421
+ end
422
+
423
+ def capture_options(options)
424
+ return options.merge(idempotency_key: "#{options[:idempotency_key]}-cap") if options[:idempotency_key]
425
+
426
+ options
427
+ end
428
+
429
+ def add_network_transaction_reference(post, options)
430
+ return unless ntid = options[:network_transaction_id] || options.dig(:stored_credential, :network_transaction_id)
431
+
432
+ post[:additionalData] = {} unless post[:additionalData]
433
+ post[:additionalData][:networkTxReference] = ntid
434
+ end
435
+
436
+ def add_reference(post, authorization, options = {})
437
+ original_reference = authorization.split('#').reject(&:empty?).first
438
+ post[:originalReference] = original_reference
439
+ end
440
+
441
+ def add_mpi_data_for_network_tokenization_card(post, payment)
442
+ post[:mpiData] = {}
443
+ post[:mpiData][:authenticationResponse] = 'Y'
444
+ post[:mpiData][:cavv] = payment.payment_cryptogram
445
+ post[:mpiData][:directoryResponse] = 'Y'
446
+ post[:mpiData][:eci] = payment.eci || '07'
447
+ end
448
+
449
+ def add_recurring_contract(post, options = {})
450
+ return unless options[:recurring_contract_type]
451
+
452
+ recurring = {
453
+ contract: options[:recurring_contract_type]
454
+ }
455
+
456
+ post[:recurring] = recurring
457
+ end
458
+
459
+ def add_application_info(post, options)
460
+ post[:applicationInfo] ||= {}
461
+ add_external_platform(post, options)
462
+ add_merchant_application(post, options)
463
+ end
464
+
465
+ def add_external_platform(post, options)
466
+ options.update(externalPlatform: application_id) if application_id
467
+
468
+ return unless options[:externalPlatform]
469
+
470
+ post[:applicationInfo][:externalPlatform] = {
471
+ name: options[:externalPlatform][:name],
472
+ version: options[:externalPlatform][:version]
473
+ }
474
+ end
475
+
476
+ def add_merchant_application(post, options)
477
+ return unless options[:merchantApplication]
478
+
479
+ post[:applicationInfo][:merchantApplication] = {
480
+ name: options[:merchantApplication][:name],
481
+ version: options[:merchantApplication][:version]
482
+ }
483
+ end
484
+
485
+ def add_installments(post, options)
486
+ post[:installments] = {
487
+ value: options[:installments]
488
+ }
489
+ end
490
+
491
+ def add_3ds(post, options)
492
+ if three_ds_2_options = options[:three_ds_2]
493
+ device_channel = three_ds_2_options[:channel]
494
+ if device_channel == 'app'
495
+ post[:threeDS2RequestData] = { deviceChannel: device_channel }
114
496
  else
115
- flat_hash[conc_key] = val
497
+ add_browser_info(three_ds_2_options[:browser_info], post)
498
+ post[:threeDS2RequestData] = { deviceChannel: device_channel, notificationURL: three_ds_2_options[:notification_url] }
499
+ end
500
+
501
+ if options.has_key?(:execute_threed)
502
+ post[:additionalData][:executeThreeD] = options[:execute_threed]
503
+ post[:additionalData][:scaExemption] = options[:sca_exemption] if options[:sca_exemption]
116
504
  end
505
+ else
506
+ return unless !options[:execute_threed].nil? || !options[:threed_dynamic].nil?
507
+
508
+ post[:browserInfo] = { userAgent: options[:user_agent], acceptHeader: options[:accept_header] } if options[:execute_threed] || options[:threed_dynamic]
509
+ post[:additionalData] ||= {}
510
+ post[:additionalData][:executeThreeD] = options[:execute_threed] if !options[:execute_threed].nil?
511
+ end
512
+ end
513
+
514
+ def add_3ds_authenticated_data(post, options)
515
+ if options[:three_d_secure] && options[:three_d_secure][:eci] && options[:three_d_secure][:xid]
516
+ add_3ds1_authenticated_data(post, options)
517
+ elsif options[:three_d_secure]
518
+ add_3ds2_authenticated_data(post, options)
117
519
  end
118
- flat_hash
119
520
  end
120
521
 
121
- def headers
122
- {
123
- 'Authorization' => 'Basic ' + Base64.encode64("ws@Company.#{@options[:company]}:#{@options[:password]}").strip
522
+ def add_3ds1_authenticated_data(post, options)
523
+ three_d_secure_options = options[:three_d_secure]
524
+ post[:mpiData] = {
525
+ cavv: three_d_secure_options[:cavv],
526
+ cavvAlgorithm: three_d_secure_options[:cavv_algorithm],
527
+ eci: three_d_secure_options[:eci],
528
+ xid: three_d_secure_options[:xid],
529
+ directoryResponse: three_d_secure_options[:enrolled],
530
+ authenticationResponse: three_d_secure_options[:authentication_response_status]
124
531
  }
125
532
  end
126
533
 
127
- def parse(response)
128
- Hash[
129
- response.split('&').map do |x|
130
- key, val = x.split('=', 2)
131
- [key.split('.').last, CGI.unescape(val)]
132
- end
133
- ]
534
+ def add_3ds2_authenticated_data(post, options)
535
+ three_d_secure_options = options[:three_d_secure]
536
+ # If the transaction was authenticated in a frictionless flow, send the transStatus from the ARes.
537
+ if three_d_secure_options[:authentication_response_status].nil?
538
+ authentication_response = three_d_secure_options[:directory_response_status]
539
+ else
540
+ authentication_response = three_d_secure_options[:authentication_response_status]
541
+ end
542
+ post[:mpiData] = {
543
+ threeDSVersion: three_d_secure_options[:version],
544
+ eci: three_d_secure_options[:eci],
545
+ cavv: three_d_secure_options[:cavv],
546
+ dsTransID: three_d_secure_options[:ds_transaction_id],
547
+ directoryResponse: three_d_secure_options[:directory_response_status],
548
+ authenticationResponse: authentication_response
549
+ }
550
+ end
551
+
552
+ def parse(body)
553
+ return {} if body.blank?
554
+
555
+ JSON.parse(body)
134
556
  end
135
557
 
136
- def post_data(data)
137
- data.map do |key, val|
138
- "#{key}=#{CGI.escape(val.to_s)}"
139
- end.reduce do |x, y|
140
- "#{x}&#{y}"
558
+ def commit(action, parameters, options)
559
+ begin
560
+ raw_response = ssl_post(url(action), post_data(action, parameters), request_headers(options))
561
+ response = parse(raw_response)
562
+ rescue ResponseError => e
563
+ raw_response = e.response.body
564
+ response = parse(raw_response)
141
565
  end
566
+
567
+ success = success_from(action, response, options)
568
+ Response.new(
569
+ success,
570
+ message_from(action, response),
571
+ response,
572
+ authorization: authorization_from(action, parameters, response),
573
+ test: test?,
574
+ error_code: success ? nil : error_code_from(response),
575
+ network_transaction_id: network_transaction_id_from(response),
576
+ avs_result: AVSResult.new(code: avs_code_from(response)),
577
+ cvv_result: CVVResult.new(cvv_result_from(response))
578
+ )
142
579
  end
143
580
 
144
- def message_from(response)
145
- return response['resultCode'] if response.has_key?('resultCode') # Payment request
146
- return response['response'] if response['response'] # Modification request
147
- "Failure" # Negative fallback in case of error
581
+ def avs_code_from(response)
582
+ AVS_MAPPING[response['additionalData']['avsResult'][0..1].strip] if response.dig('additionalData', 'avsResult')
148
583
  end
149
584
 
150
- def success_from(response)
151
- return true if response.has_key?('authCode')
585
+ def cvv_result_from(response)
586
+ CVC_MAPPING[response['additionalData']['cvcResult'][0]] if response.dig('additionalData', 'cvcResult')
587
+ end
152
588
 
153
- successful_responses = %w([capture-received] [cancel-received] [refund-received])
154
- successful_responses.include?(response['response'])
589
+ def endpoint(action)
590
+ recurring = %w(disable storeToken).include?(action)
591
+ recurring ? "Recurring/#{RECURRING_API_VERSION}/#{action}" : "Payment/#{PAYMENT_API_VERSION}/#{action}"
155
592
  end
156
593
 
157
- def url
158
- test? ? self.test_url : self.live_url
594
+ def url(action)
595
+ if test?
596
+ "#{test_url}#{endpoint(action)}"
597
+ elsif @options[:subdomain]
598
+ "https://#{@options[:subdomain]}-pal-live.adyenpayments.com/pal/servlet/#{endpoint(action)}"
599
+ else
600
+ "#{live_url}#{endpoint(action)}"
601
+ end
159
602
  end
160
603
 
161
- def address_hash(address)
162
- full_address = "#{address[:address1]} #{address[:address2]}"
604
+ def basic_auth
605
+ Base64.strict_encode64("#{@username}:#{@password}")
606
+ end
163
607
 
164
- {
165
- :city => address[:city],
166
- :street => full_address.split(/\s+/).keep_if { |x| x !~ /\d/ }.join(' '),
167
- :houseNumberOrName => full_address.split(/\s+/).keep_if { |x| x =~ /\d/ }.join(' '),
168
- :postalCode => address[:zip],
169
- :stateOrProvince => address[:state],
170
- :country => address[:country]
608
+ def request_headers(options)
609
+ headers = {
610
+ 'Content-Type' => 'application/json',
611
+ 'Authorization' => "Basic #{basic_auth}"
171
612
  }
613
+ headers['Idempotency-Key'] = options[:idempotency_key] if options[:idempotency_key]
614
+ headers
172
615
  end
173
616
 
174
- def amount_hash(money, currency)
175
- {
176
- :currency => (currency || currency(money)),
177
- :value => amount(money)
178
- }
617
+ def success_from(action, response, options)
618
+ if %w[RedirectShopper ChallengeShopper].include?(response.dig('resultCode')) && !options[:execute_threed] && !options[:threed_dynamic]
619
+ response['refusalReason'] = 'Received unexpected 3DS authentication response. Use the execute_threed and/or threed_dynamic options to initiate a proper 3DS flow.'
620
+ return false
621
+ end
622
+ case action.to_s
623
+ when 'authorise', 'authorise3d'
624
+ %w[Authorised Received RedirectShopper].include?(response['resultCode'])
625
+ when 'capture', 'refund', 'cancel', 'cancelOrRefund'
626
+ response['response'] == "[#{action}-received]"
627
+ when 'adjustAuthorisation'
628
+ response['response'] == 'Authorised' || response['response'] == '[adjustAuthorisation-received]'
629
+ when 'storeToken'
630
+ response['result'] == 'Success'
631
+ when 'disable'
632
+ response['response'] == '[detail-successfully-disabled]'
633
+ when 'refundWithData'
634
+ response['resultCode'] == 'Received'
635
+ else
636
+ false
637
+ end
638
+ end
639
+
640
+ def message_from(action, response)
641
+ return authorize_message_from(response) if %w(authorise authorise3d authorise3ds2).include?(action.to_s)
642
+
643
+ response['response'] || response['message'] || response['result'] || response['resultCode']
644
+ end
645
+
646
+ def authorize_message_from(response)
647
+ if response['refusalReason'] && response['additionalData'] && response['additionalData']['refusalReasonRaw']
648
+ "#{response['refusalReason']} | #{response['additionalData']['refusalReasonRaw']}"
649
+ else
650
+ response['refusalReason'] || response['resultCode'] || response['message'] || response['result']
651
+ end
652
+ end
653
+
654
+ def authorization_from(action, parameters, response)
655
+ return nil if response['pspReference'].nil?
656
+
657
+ recurring = response['additionalData']['recurring.recurringDetailReference'] if response['additionalData']
658
+ recurring = response['recurringDetailReference'] if action == 'storeToken'
659
+
660
+ "#{parameters[:originalReference]}##{response['pspReference']}##{recurring}"
179
661
  end
180
662
 
181
- def credit_card_hash(creditcard)
182
- {
183
- :cvc => creditcard.verification_value,
184
- :expiryMonth => format(creditcard.month, :two_digits),
185
- :expiryYear => format(creditcard.year, :four_digits),
186
- :holderName => creditcard.name,
187
- :number => creditcard.number
663
+ def init_post(options = {})
664
+ post = {}
665
+ add_merchant_account(post, options)
666
+ post[:reference] = options[:order_id][0..79] if options[:order_id]
667
+ post
668
+ end
669
+
670
+ def post_data(action, parameters = {})
671
+ JSON.generate(parameters)
672
+ end
673
+
674
+ def error_code_from(response)
675
+ STANDARD_ERROR_CODE_MAPPING[response['errorCode']] || response['errorCode']
676
+ end
677
+
678
+ def network_transaction_id_from(response)
679
+ response.dig('additionalData', 'networkTxReference')
680
+ end
681
+
682
+ def add_browser_info(browser_info, post)
683
+ return unless browser_info
684
+
685
+ post[:browserInfo] = {
686
+ acceptHeader: browser_info[:accept_header],
687
+ colorDepth: browser_info[:depth],
688
+ javaEnabled: browser_info[:java],
689
+ language: browser_info[:language],
690
+ screenHeight: browser_info[:height],
691
+ screenWidth: browser_info[:width],
692
+ timeZoneOffset: browser_info[:timezone],
693
+ userAgent: browser_info[:user_agent]
188
694
  }
189
695
  end
190
696
 
191
- def modification_request(reference, options)
192
- {
193
- :merchantAccount => @options[:merchant],
194
- :originalReference => reference
195
- }.keep_if { |_, v| v }
697
+ def unsupported_failure_response(initial_response)
698
+ Response.new(
699
+ false,
700
+ 'Recurring transactions are not supported for this card type.',
701
+ initial_response.params,
702
+ authorization: initial_response.authorization,
703
+ test: initial_response.test,
704
+ error_code: initial_response.error_code,
705
+ avs_result: initial_response.avs_result,
706
+ cvv_result: initial_response.cvv_result[:code]
707
+ )
196
708
  end
197
709
 
198
- def payment_request(money, options)
199
- {
200
- :merchantAccount => @options[:merchant],
201
- :reference => options[:order_id],
202
- :shopperEmail => options[:email],
203
- :shopperIP => options[:ip],
204
- :shopperReference => options[:customer]
205
- }.keep_if { |_, v| v }
710
+ def card_not_stored?(response)
711
+ response.authorization ? response.authorization.split('#')[2].nil? : true
206
712
  end
207
713
  end
208
714
  end