activemerchant 1.79.2 → 1.129.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (279) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG +1391 -0
  3. data/README.md +29 -14
  4. data/lib/active_merchant/billing/avs_result.rb +25 -28
  5. data/lib/active_merchant/billing/base.rb +0 -13
  6. data/lib/active_merchant/billing/check.rb +55 -22
  7. data/lib/active_merchant/billing/compatibility.rb +10 -12
  8. data/lib/active_merchant/billing/credit_card.rb +82 -62
  9. data/lib/active_merchant/billing/credit_card_formatting.rb +4 -4
  10. data/lib/active_merchant/billing/credit_card_methods.rb +328 -58
  11. data/lib/active_merchant/billing/cvv_result.rb +0 -1
  12. data/lib/active_merchant/billing/gateway.rb +61 -56
  13. data/lib/active_merchant/billing/gateways/adyen.rb +562 -87
  14. data/lib/active_merchant/billing/gateways/airwallex.rb +370 -0
  15. data/lib/active_merchant/billing/gateways/alelo.rb +256 -0
  16. data/lib/active_merchant/billing/gateways/allied_wallet.rb +35 -36
  17. data/lib/active_merchant/billing/gateways/authorize_net.rb +297 -196
  18. data/lib/active_merchant/billing/gateways/authorize_net_arb.rb +31 -24
  19. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +94 -98
  20. data/lib/active_merchant/billing/gateways/axcessms.rb +64 -66
  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 +12 -12
  25. data/lib/active_merchant/billing/gateways/barclaycard_smartpay.rb +140 -69
  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 +115 -115
  29. data/lib/active_merchant/billing/gateways/beanstream.rb +39 -13
  30. data/lib/active_merchant/billing/gateways/beanstream_interac.rb +1 -2
  31. data/lib/active_merchant/billing/gateways/blue_pay.rb +87 -58
  32. data/lib/active_merchant/billing/gateways/blue_snap.rb +405 -104
  33. data/lib/active_merchant/billing/gateways/bogus.rb +34 -30
  34. data/lib/active_merchant/billing/gateways/borgun.rb +97 -47
  35. data/lib/active_merchant/billing/gateways/bpoint.rb +20 -20
  36. data/lib/active_merchant/billing/gateways/braintree/braintree_common.rb +9 -3
  37. data/lib/active_merchant/billing/gateways/braintree/token_nonce.rb +113 -0
  38. data/lib/active_merchant/billing/gateways/braintree.rb +1 -1
  39. data/lib/active_merchant/billing/gateways/braintree_blue.rb +561 -259
  40. data/lib/active_merchant/billing/gateways/braintree_orange.rb +1 -1
  41. data/lib/active_merchant/billing/gateways/bridge_pay.rb +53 -54
  42. data/lib/active_merchant/billing/gateways/cams.rb +31 -31
  43. data/lib/active_merchant/billing/gateways/card_connect.rb +85 -33
  44. data/lib/active_merchant/billing/gateways/card_save.rb +7 -9
  45. data/lib/active_merchant/billing/gateways/card_stream.rb +187 -169
  46. data/lib/active_merchant/billing/gateways/cardknox.rb +24 -25
  47. data/lib/active_merchant/billing/gateways/cardprocess.rb +9 -7
  48. data/lib/active_merchant/billing/gateways/cashnet.rb +43 -27
  49. data/lib/active_merchant/billing/gateways/cc5.rb +14 -17
  50. data/lib/active_merchant/billing/gateways/cecabank.rb +62 -52
  51. data/lib/active_merchant/billing/gateways/cenpos.rb +63 -62
  52. data/lib/active_merchant/billing/gateways/checkout.rb +21 -23
  53. data/lib/active_merchant/billing/gateways/checkout_v2.rb +391 -113
  54. data/lib/active_merchant/billing/gateways/citrus_pay.rb +1 -3
  55. data/lib/active_merchant/billing/gateways/clearhaus.rb +40 -41
  56. data/lib/active_merchant/billing/gateways/commerce_hub.rb +361 -0
  57. data/lib/active_merchant/billing/gateways/commercegate.rb +11 -12
  58. data/lib/active_merchant/billing/gateways/conekta.rb +35 -30
  59. data/lib/active_merchant/billing/gateways/creditcall.rb +59 -59
  60. data/lib/active_merchant/billing/gateways/credorax.rb +326 -145
  61. data/lib/active_merchant/billing/gateways/ct_payment.rb +269 -0
  62. data/lib/active_merchant/billing/gateways/culqi.rb +53 -53
  63. data/lib/active_merchant/billing/gateways/cyber_source/cyber_source_common.rb +36 -0
  64. data/lib/active_merchant/billing/gateways/cyber_source.rb +566 -208
  65. data/lib/active_merchant/billing/gateways/cyber_source_rest.rb +456 -0
  66. data/lib/active_merchant/billing/gateways/d_local.rb +342 -0
  67. data/lib/active_merchant/billing/gateways/data_cash.rb +40 -56
  68. data/lib/active_merchant/billing/gateways/decidir.rb +358 -0
  69. data/lib/active_merchant/billing/gateways/decidir_plus.rb +344 -0
  70. data/lib/active_merchant/billing/gateways/dibs.rb +34 -40
  71. data/lib/active_merchant/billing/gateways/digitzs.rb +48 -45
  72. data/lib/active_merchant/billing/gateways/ebanx.rb +110 -60
  73. data/lib/active_merchant/billing/gateways/efsnet.rb +46 -50
  74. data/lib/active_merchant/billing/gateways/elavon.rb +351 -189
  75. data/lib/active_merchant/billing/gateways/element.rb +106 -56
  76. data/lib/active_merchant/billing/gateways/epay.rb +74 -64
  77. data/lib/active_merchant/billing/gateways/evo_ca.rb +13 -14
  78. data/lib/active_merchant/billing/gateways/eway.rb +74 -73
  79. data/lib/active_merchant/billing/gateways/eway_managed.rb +85 -87
  80. data/lib/active_merchant/billing/gateways/eway_rapid.rb +105 -60
  81. data/lib/active_merchant/billing/gateways/exact.rb +29 -37
  82. data/lib/active_merchant/billing/gateways/ezic.rb +21 -22
  83. data/lib/active_merchant/billing/gateways/fat_zebra.rb +70 -48
  84. data/lib/active_merchant/billing/gateways/federated_canada.rb +11 -13
  85. data/lib/active_merchant/billing/gateways/finansbank.rb +3 -4
  86. data/lib/active_merchant/billing/gateways/first_giving.rb +23 -23
  87. data/lib/active_merchant/billing/gateways/first_pay.rb +33 -13
  88. data/lib/active_merchant/billing/gateways/firstdata_e4.rb +106 -105
  89. data/lib/active_merchant/billing/gateways/firstdata_e4_v27.rb +505 -0
  90. data/lib/active_merchant/billing/gateways/flo2cash.rb +36 -36
  91. data/lib/active_merchant/billing/gateways/flo2cash_simple.rb +2 -2
  92. data/lib/active_merchant/billing/gateways/forte.rb +70 -40
  93. data/lib/active_merchant/billing/gateways/garanti.rb +24 -31
  94. data/lib/active_merchant/billing/gateways/global_collect.rb +378 -154
  95. data/lib/active_merchant/billing/gateways/global_transport.rb +12 -13
  96. data/lib/active_merchant/billing/gateways/hdfc.rb +55 -57
  97. data/lib/active_merchant/billing/gateways/hps.rb +236 -69
  98. data/lib/active_merchant/billing/gateways/iats_payments.rb +61 -39
  99. data/lib/active_merchant/billing/gateways/in_context_paypal_express.rb +1 -1
  100. data/lib/active_merchant/billing/gateways/inspire.rb +41 -47
  101. data/lib/active_merchant/billing/gateways/instapay.rb +10 -14
  102. data/lib/active_merchant/billing/gateways/ipg.rb +420 -0
  103. data/lib/active_merchant/billing/gateways/ipp.rb +25 -24
  104. data/lib/active_merchant/billing/gateways/iridium.rb +243 -244
  105. data/lib/active_merchant/billing/gateways/itransact.rb +14 -14
  106. data/lib/active_merchant/billing/gateways/iveri.rb +73 -34
  107. data/lib/active_merchant/billing/gateways/ixopay.rb +320 -0
  108. data/lib/active_merchant/billing/gateways/jetpay.rb +145 -152
  109. data/lib/active_merchant/billing/gateways/jetpay_v2.rb +154 -159
  110. data/lib/active_merchant/billing/gateways/komoju.rb +16 -16
  111. data/lib/active_merchant/billing/gateways/kushki.rb +127 -57
  112. data/lib/active_merchant/billing/gateways/latitude19.rb +111 -115
  113. data/lib/active_merchant/billing/gateways/linkpoint.rb +82 -85
  114. data/lib/active_merchant/billing/gateways/litle.rb +247 -53
  115. data/lib/active_merchant/billing/gateways/mastercard.rb +41 -23
  116. data/lib/active_merchant/billing/gateways/maxipago.rb +5 -5
  117. data/lib/active_merchant/billing/gateways/mercado_pago.rb +135 -49
  118. data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +62 -29
  119. data/lib/active_merchant/billing/gateways/merchant_one.rb +16 -20
  120. data/lib/active_merchant/billing/gateways/merchant_partners.rb +40 -40
  121. data/lib/active_merchant/billing/gateways/merchant_ware.rb +54 -60
  122. data/lib/active_merchant/billing/gateways/merchant_ware_version_four.rb +42 -44
  123. data/lib/active_merchant/billing/gateways/merchant_warrior.rb +52 -14
  124. data/lib/active_merchant/billing/gateways/mercury.rb +47 -51
  125. data/lib/active_merchant/billing/gateways/metrics_global.rb +32 -42
  126. data/lib/active_merchant/billing/gateways/micropayment.rb +42 -45
  127. data/lib/active_merchant/billing/gateways/migs/migs_codes.rb +7 -7
  128. data/lib/active_merchant/billing/gateways/migs.rb +45 -40
  129. data/lib/active_merchant/billing/gateways/mit.rb +260 -0
  130. data/lib/active_merchant/billing/gateways/modern_payments.rb +2 -2
  131. data/lib/active_merchant/billing/gateways/modern_payments_cim.rb +29 -31
  132. data/lib/active_merchant/billing/gateways/moka.rb +290 -0
  133. data/lib/active_merchant/billing/gateways/monei.rb +255 -138
  134. data/lib/active_merchant/billing/gateways/moneris.rb +226 -88
  135. data/lib/active_merchant/billing/gateways/money_movers.rb +11 -13
  136. data/lib/active_merchant/billing/gateways/mundipagg.rb +117 -43
  137. data/lib/active_merchant/billing/gateways/nab_transact.rb +28 -31
  138. data/lib/active_merchant/billing/gateways/ncr_secure_pay.rb +13 -15
  139. data/lib/active_merchant/billing/gateways/net_registry.rb +12 -12
  140. data/lib/active_merchant/billing/gateways/netaxept.rb +33 -34
  141. data/lib/active_merchant/billing/gateways/netbanx.rb +167 -80
  142. data/lib/active_merchant/billing/gateways/netbilling.rb +27 -30
  143. data/lib/active_merchant/billing/gateways/netpay.rb +10 -10
  144. data/lib/active_merchant/billing/gateways/network_merchants.rb +7 -11
  145. data/lib/active_merchant/billing/gateways/nmi.rb +134 -48
  146. data/lib/active_merchant/billing/gateways/ogone.rb +88 -58
  147. data/lib/active_merchant/billing/gateways/omise.rb +30 -31
  148. data/lib/active_merchant/billing/gateways/openpay.rb +45 -26
  149. data/lib/active_merchant/billing/gateways/opp.rb +166 -144
  150. data/lib/active_merchant/billing/gateways/optimal_payment.rb +67 -64
  151. data/lib/active_merchant/billing/gateways/orbital/orbital_soft_descriptors.rb +5 -7
  152. data/lib/active_merchant/billing/gateways/orbital.rb +726 -382
  153. data/lib/active_merchant/billing/gateways/pac_net_raven.rb +26 -27
  154. data/lib/active_merchant/billing/gateways/pagarme.rb +47 -56
  155. data/lib/active_merchant/billing/gateways/pago_facil.rb +12 -14
  156. data/lib/active_merchant/billing/gateways/pay_arc.rb +392 -0
  157. data/lib/active_merchant/billing/gateways/pay_conex.rb +39 -40
  158. data/lib/active_merchant/billing/gateways/pay_gate_xml.rb +65 -65
  159. data/lib/active_merchant/billing/gateways/pay_hub.rb +39 -39
  160. data/lib/active_merchant/billing/gateways/pay_junction.rb +37 -37
  161. data/lib/active_merchant/billing/gateways/pay_junction_v2.rb +70 -54
  162. data/lib/active_merchant/billing/gateways/pay_secure.rb +15 -17
  163. data/lib/active_merchant/billing/gateways/pay_trace.rb +450 -0
  164. data/lib/active_merchant/billing/gateways/paybox_direct.rb +71 -47
  165. data/lib/active_merchant/billing/gateways/payeezy.rb +159 -32
  166. data/lib/active_merchant/billing/gateways/payex.rb +39 -42
  167. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +41 -36
  168. data/lib/active_merchant/billing/gateways/payflow/payflow_express_response.rb +11 -8
  169. data/lib/active_merchant/billing/gateways/payflow/payflow_response.rb +3 -3
  170. data/lib/active_merchant/billing/gateways/payflow.rb +178 -54
  171. data/lib/active_merchant/billing/gateways/payflow_express.rb +61 -65
  172. data/lib/active_merchant/billing/gateways/payflow_express_uk.rb +0 -1
  173. data/lib/active_merchant/billing/gateways/payflow_uk.rb +1 -2
  174. data/lib/active_merchant/billing/gateways/payment_express.rb +66 -58
  175. data/lib/active_merchant/billing/gateways/paymentez.rb +114 -25
  176. data/lib/active_merchant/billing/gateways/paymill.rb +134 -133
  177. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +2 -1
  178. data/lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb +4 -0
  179. data/lib/active_merchant/billing/gateways/paypal.rb +27 -14
  180. data/lib/active_merchant/billing/gateways/paypal_ca.rb +1 -1
  181. data/lib/active_merchant/billing/gateways/paypal_digital_goods.rb +2 -2
  182. data/lib/active_merchant/billing/gateways/paypal_express.rb +5 -2
  183. data/lib/active_merchant/billing/gateways/paypal_express_common.rb +1 -1
  184. data/lib/active_merchant/billing/gateways/paysafe.rb +420 -0
  185. data/lib/active_merchant/billing/gateways/payscout.rb +10 -13
  186. data/lib/active_merchant/billing/gateways/paystation.rb +79 -82
  187. data/lib/active_merchant/billing/gateways/payu_in.rb +59 -58
  188. data/lib/active_merchant/billing/gateways/payu_latam.rb +139 -97
  189. data/lib/active_merchant/billing/gateways/payway.rb +27 -27
  190. data/lib/active_merchant/billing/gateways/payway_dot_com.rb +253 -0
  191. data/lib/active_merchant/billing/gateways/pin.rb +87 -34
  192. data/lib/active_merchant/billing/gateways/plexo.rb +308 -0
  193. data/lib/active_merchant/billing/gateways/plugnpay.rb +82 -82
  194. data/lib/active_merchant/billing/gateways/priority.rb +392 -0
  195. data/lib/active_merchant/billing/gateways/pro_pay.rb +139 -140
  196. data/lib/active_merchant/billing/gateways/psigate.rb +44 -44
  197. data/lib/active_merchant/billing/gateways/psl_card.rb +29 -37
  198. data/lib/active_merchant/billing/gateways/qbms.rb +75 -76
  199. data/lib/active_merchant/billing/gateways/quantum.rb +21 -23
  200. data/lib/active_merchant/billing/gateways/quickbooks.rb +142 -55
  201. data/lib/active_merchant/billing/gateways/quickpay/quickpay_common.rb +103 -107
  202. data/lib/active_merchant/billing/gateways/quickpay/quickpay_v10.rb +156 -158
  203. data/lib/active_merchant/billing/gateways/quickpay/quickpay_v4to7.rb +7 -8
  204. data/lib/active_merchant/billing/gateways/quickpay.rb +1 -3
  205. data/lib/active_merchant/billing/gateways/qvalent.rb +137 -68
  206. data/lib/active_merchant/billing/gateways/rapyd.rb +319 -0
  207. data/lib/active_merchant/billing/gateways/reach.rb +277 -0
  208. data/lib/active_merchant/billing/gateways/realex.rb +132 -50
  209. data/lib/active_merchant/billing/gateways/redsys.rb +382 -186
  210. data/lib/active_merchant/billing/gateways/s5.rb +16 -16
  211. data/lib/active_merchant/billing/gateways/safe_charge.rb +83 -47
  212. data/lib/active_merchant/billing/gateways/sage.rb +49 -48
  213. data/lib/active_merchant/billing/gateways/sage_pay.rb +76 -83
  214. data/lib/active_merchant/billing/gateways/sallie_mae.rb +13 -15
  215. data/lib/active_merchant/billing/gateways/secure_net.rb +32 -40
  216. data/lib/active_merchant/billing/gateways/secure_pay.rb +30 -40
  217. data/lib/active_merchant/billing/gateways/secure_pay_au.rb +23 -26
  218. data/lib/active_merchant/billing/gateways/secure_pay_tech.rb +14 -16
  219. data/lib/active_merchant/billing/gateways/securion_pay.rb +69 -31
  220. data/lib/active_merchant/billing/gateways/shift4.rb +342 -0
  221. data/lib/active_merchant/billing/gateways/simetrik.rb +368 -0
  222. data/lib/active_merchant/billing/gateways/skip_jack.rb +52 -53
  223. data/lib/active_merchant/billing/gateways/smart_ps.rb +51 -60
  224. data/lib/active_merchant/billing/gateways/so_easy_pay.rb +29 -29
  225. data/lib/active_merchant/billing/gateways/spreedly_core.rb +66 -47
  226. data/lib/active_merchant/billing/gateways/stripe.rb +309 -148
  227. data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +556 -0
  228. data/lib/active_merchant/billing/gateways/swipe_checkout.rb +18 -23
  229. data/lib/active_merchant/billing/gateways/telr.rb +46 -48
  230. data/lib/active_merchant/billing/gateways/tns.rb +8 -7
  231. data/lib/active_merchant/billing/gateways/trans_first.rb +37 -37
  232. data/lib/active_merchant/billing/gateways/trans_first_transaction_express.rb +249 -245
  233. data/lib/active_merchant/billing/gateways/transact_pro.rb +25 -27
  234. data/lib/active_merchant/billing/gateways/transax.rb +6 -8
  235. data/lib/active_merchant/billing/gateways/transnational.rb +1 -2
  236. data/lib/active_merchant/billing/gateways/trexle.rb +22 -18
  237. data/lib/active_merchant/billing/gateways/trust_commerce.rb +161 -88
  238. data/lib/active_merchant/billing/gateways/usa_epay.rb +5 -6
  239. data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +231 -238
  240. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +129 -55
  241. data/lib/active_merchant/billing/gateways/vanco.rb +42 -33
  242. data/lib/active_merchant/billing/gateways/verifi.rb +52 -53
  243. data/lib/active_merchant/billing/gateways/viaklix.rb +18 -22
  244. data/lib/active_merchant/billing/gateways/visanet_peru.rb +115 -74
  245. data/lib/active_merchant/billing/gateways/vpos.rb +223 -0
  246. data/lib/active_merchant/billing/gateways/webpay.rb +9 -9
  247. data/lib/active_merchant/billing/gateways/wepay.rb +38 -41
  248. data/lib/active_merchant/billing/gateways/wirecard.rb +36 -37
  249. data/lib/active_merchant/billing/gateways/wompi.rb +197 -0
  250. data/lib/active_merchant/billing/gateways/world_net.rb +39 -38
  251. data/lib/active_merchant/billing/gateways/worldpay.rb +756 -142
  252. data/lib/active_merchant/billing/gateways/worldpay_online_payments.rb +73 -83
  253. data/lib/active_merchant/billing/gateways/worldpay_us.rb +31 -31
  254. data/lib/active_merchant/billing/model.rb +2 -2
  255. data/lib/active_merchant/billing/network_tokenization_credit_card.rb +3 -3
  256. data/lib/active_merchant/billing/rails.rb +1 -1
  257. data/lib/active_merchant/billing/response.rb +32 -13
  258. data/lib/active_merchant/billing/three_d_secure_eci_mapper.rb +27 -0
  259. data/lib/active_merchant/billing.rb +1 -0
  260. data/lib/active_merchant/connection.rb +24 -38
  261. data/lib/active_merchant/country.rb +9 -5
  262. data/lib/active_merchant/errors.rb +4 -1
  263. data/lib/active_merchant/net_http_ssl_connection.rb +2 -0
  264. data/lib/active_merchant/network_connection_retries.rb +28 -31
  265. data/lib/active_merchant/post_data.rb +5 -3
  266. data/lib/active_merchant/posts_data.rb +5 -7
  267. data/lib/active_merchant/version.rb +1 -1
  268. data/lib/active_merchant.rb +3 -3
  269. data/lib/activemerchant.rb +1 -1
  270. data/lib/certs/cacert.pem +1592 -2329
  271. data/lib/support/gateway_support.rb +8 -10
  272. data/lib/support/ssl_verify.rb +9 -14
  273. data/lib/support/ssl_version.rb +9 -10
  274. metadata +98 -37
  275. data/lib/active_merchant/billing/gateways/ideal/ideal_base.rb +0 -246
  276. data/lib/active_merchant/billing/gateways/ideal/ideal_rabobank.pem +0 -13
  277. data/lib/active_merchant/billing/gateways/ideal/ideal_response.rb +0 -29
  278. data/lib/active_merchant/billing/gateways/ideal_rabobank.rb +0 -66
  279. data/lib/active_merchant/billing/gateways/moneris_us.rb +0 -309
@@ -1,7 +1,7 @@
1
1
  module ActiveMerchant #:nodoc:
2
2
  module Billing #:nodoc:
3
3
  # Initial setup instructions can be found in
4
- # http://cybersource.com/support_center/implementation/downloads/soap_api/SOAP_toolkits.pdf
4
+ # http://apps.cybersource.com/library/documentation/dev_guides/SOAP_Toolkits/SOAP_toolkits.pdf
5
5
  #
6
6
  # Important Notes
7
7
  # * For checks you can purchase and store.
@@ -15,19 +15,28 @@ module ActiveMerchant #:nodoc:
15
15
  # CyberSource what kind of item you are selling. It is used when
16
16
  # calculating tax/VAT.
17
17
  # * All transactions use dollar values.
18
- # * To process pinless debit cards through the pinless debit card
19
- # network, your Cybersource merchant account must accept pinless
20
- # debit card payments.
21
18
  # * The order of the XML elements does matter, make sure to follow the order in
22
19
  # the documentation exactly.
23
20
  class CyberSourceGateway < Gateway
24
21
  self.test_url = 'https://ics2wstesta.ic3.com/commerce/1.x/transactionProcessor'
25
22
  self.live_url = 'https://ics2wsa.ic3.com/commerce/1.x/transactionProcessor'
26
23
 
27
- XSD_VERSION = "1.121"
28
-
29
- self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb, :switch, :dankort, :maestro]
30
- self.supported_countries = %w(US BR CA CN DK FI FR DE JP MX NO SE GB SG LB)
24
+ # Schema files can be found here: https://ics2ws.ic3.com/commerce/1.x/transactionProcessor/
25
+ TEST_XSD_VERSION = '1.201'
26
+ PRODUCTION_XSD_VERSION = '1.201'
27
+ ECI_BRAND_MAPPING = {
28
+ visa: 'vbv',
29
+ master: 'spa',
30
+ maestro: 'spa',
31
+ american_express: 'aesk',
32
+ jcb: 'js',
33
+ discover: 'pb',
34
+ diners_club: 'pb'
35
+ }.freeze
36
+ DEFAULT_COLLECTION_INDICATOR = 2
37
+
38
+ self.supported_cardtypes = %i[visa master american_express discover diners_club jcb dankort maestro elo]
39
+ self.supported_countries = %w(US AE BR CA CN DK FI FR DE IN JP MX NO SE GB SG LB PK)
31
40
 
32
41
  self.default_currency = 'USD'
33
42
  self.currencies_without_fractions = %w(JPY)
@@ -36,56 +45,91 @@ module ActiveMerchant #:nodoc:
36
45
  self.display_name = 'CyberSource'
37
46
 
38
47
  @@credit_card_codes = {
39
- :visa => '001',
40
- :master => '002',
41
- :american_express => '003',
42
- :discover => '004',
43
- :diners_club => '005',
44
- :jcb => '007',
45
- :switch => '024',
46
- :dankort => '034',
47
- :maestro => '042'
48
+ visa: '001',
49
+ master: '002',
50
+ american_express: '003',
51
+ discover: '004',
52
+ diners_club: '005',
53
+ jcb: '007',
54
+ dankort: '034',
55
+ maestro: '042',
56
+ elo: '054'
57
+ }
58
+
59
+ @@decision_codes = {
60
+ accept: 'ACCEPT',
61
+ review: 'REVIEW'
48
62
  }
49
63
 
50
64
  @@response_codes = {
51
- :r100 => "Successful transaction",
52
- :r101 => "Request is missing one or more required fields" ,
53
- :r102 => "One or more fields contains invalid data",
54
- :r150 => "General failure",
55
- :r151 => "The request was received but a server time-out occurred",
56
- :r152 => "The request was received, but a service timed out",
57
- :r200 => "The authorization request was approved by the issuing bank but declined by CyberSource because it did not pass the AVS check",
58
- :r201 => "The issuing bank has questions about the request",
59
- :r202 => "Expired card",
60
- :r203 => "General decline of the card",
61
- :r204 => "Insufficient funds in the account",
62
- :r205 => "Stolen or lost card",
63
- :r207 => "Issuing bank unavailable",
64
- :r208 => "Inactive card or card not authorized for card-not-present transactions",
65
- :r209 => "American Express Card Identifiction Digits (CID) did not match",
66
- :r210 => "The card has reached the credit limit",
67
- :r211 => "Invalid card verification number",
68
- :r221 => "The customer matched an entry on the processor's negative file",
69
- :r230 => "The authorization request was approved by the issuing bank but declined by CyberSource because it did not pass the card verification check",
70
- :r231 => "Invalid account number",
71
- :r232 => "The card type is not accepted by the payment processor",
72
- :r233 => "General decline by the processor",
73
- :r234 => "A problem exists with your CyberSource merchant configuration",
74
- :r235 => "The requested amount exceeds the originally authorized amount",
75
- :r236 => "Processor failure",
76
- :r237 => "The authorization has already been reversed",
77
- :r238 => "The authorization has already been captured",
78
- :r239 => "The requested transaction amount must match the previous transaction amount",
79
- :r240 => "The card type sent is invalid or does not correlate with the credit card number",
80
- :r241 => "The request ID is invalid",
81
- :r242 => "You requested a capture, but there is no corresponding, unused authorization record.",
82
- :r243 => "The transaction has already been settled or reversed",
83
- :r244 => "The bank account number failed the validation check",
84
- :r246 => "The capture or credit is not voidable because the capture or credit information has already been submitted to your processor",
85
- :r247 => "You requested a credit for a capture that was previously voided",
86
- :r250 => "The request was received, but a time-out occurred with the payment processor",
87
- :r254 => "Your CyberSource account is prohibited from processing stand-alone refunds",
88
- :r255 => "Your CyberSource account is not configured to process the service in the country you specified"
65
+ r100: 'Successful transaction',
66
+ r101: 'Request is missing one or more required fields',
67
+ r102: 'One or more fields contains invalid data',
68
+ r104: 'The merchantReferenceCode sent with this authorization request matches the merchantReferenceCode of another authorization request that you sent in the last 15 minutes.', r110: 'Partial amount was approved',
69
+ r150: 'General failure',
70
+ r151: 'The request was received but a server time-out occurred',
71
+ r152: 'The request was received, but a service timed out',
72
+ r200: 'The authorization request was approved by the issuing bank but declined by CyberSource because it did not pass the AVS check',
73
+ r201: 'The issuing bank has questions about the request',
74
+ r202: 'Expired card',
75
+ r203: 'General decline of the card',
76
+ r204: 'Insufficient funds in the account',
77
+ r205: 'Stolen or lost card',
78
+ r207: 'Issuing bank unavailable',
79
+ r208: 'Inactive card or card not authorized for card-not-present transactions',
80
+ r209: 'American Express Card Identifiction Digits (CID) did not match',
81
+ r210: 'The card has reached the credit limit',
82
+ r211: 'Invalid card verification number',
83
+ r220: 'Generic Decline.',
84
+ r221: "The customer matched an entry on the processor's negative file",
85
+ r222: 'customer\'s account is frozen',
86
+ r230: 'The authorization request was approved by the issuing bank but declined by CyberSource because it did not pass the card verification check',
87
+ r231: 'Invalid account number',
88
+ r232: 'The card type is not accepted by the payment processor',
89
+ r233: 'General decline by the processor',
90
+ r234: 'A problem exists with your CyberSource merchant configuration',
91
+ r235: 'The requested amount exceeds the originally authorized amount',
92
+ r236: 'Processor failure',
93
+ r237: 'The authorization has already been reversed',
94
+ r238: 'The authorization has already been captured',
95
+ r239: 'The requested transaction amount must match the previous transaction amount',
96
+ r240: 'The card type sent is invalid or does not correlate with the credit card number',
97
+ r241: 'The request ID is invalid',
98
+ r242: 'You requested a capture, but there is no corresponding, unused authorization record.',
99
+ r243: 'The transaction has already been settled or reversed',
100
+ r244: 'The bank account number failed the validation check',
101
+ r246: 'The capture or credit is not voidable because the capture or credit information has already been submitted to your processor',
102
+ r247: 'You requested a credit for a capture that was previously voided',
103
+ r248: 'The boleto request was declined by your processor.',
104
+ r250: 'The request was received, but a time-out occurred with the payment processor',
105
+ r251: 'The Pinless Debit card\'s use frequency or maximum amount per use has been exceeded.',
106
+ r254: 'Your CyberSource account is prohibited from processing stand-alone refunds',
107
+ r255: 'Your CyberSource account is not configured to process the service in the country you specified',
108
+ r400: 'Soft Decline - Fraud score exceeds threshold.',
109
+ r450: 'Apartment number missing or not found.',
110
+ r451: 'Insufficient address information.',
111
+ r452: 'House/Box number not found on street.',
112
+ r453: 'Multiple address matches were found.',
113
+ r454: 'P.O. Box identifier not found or out of range.',
114
+ r455: 'Route service identifier not found or out of range.',
115
+ r456: 'Street name not found in Postal code.',
116
+ r457: 'Postal code not found in database.',
117
+ r458: 'Unable to verify or correct address.',
118
+ r459: 'Multiple addres matches were found (international)',
119
+ r460: 'Address match not found (no reason given)',
120
+ r461: 'Unsupported character set',
121
+ r475: 'The cardholder is enrolled in Payer Authentication. Please authenticate the cardholder before continuing with the transaction.',
122
+ r476: 'Encountered a Payer Authentication problem. Payer could not be authenticated.',
123
+ r478: 'Strong customer authentication (SCA) is required for this transaction.',
124
+ r480: 'The order is marked for review by Decision Manager',
125
+ r481: 'The order has been rejected by Decision Manager',
126
+ r490: 'Your aggregator or acquirer is not accepting transactions from you at this time.',
127
+ r491: 'Your aggregator or acquirer is not accepting this transaction.',
128
+ r520: 'Soft Decline - The authorization request was approved by the issuing bank but declined by CyberSource based on your Smart Authorization settings.',
129
+ r700: 'The customer matched the Denied Parties List',
130
+ r701: 'Export bill_country/ship_country match',
131
+ r702: 'Export email_country match',
132
+ r703: 'Export hostname_country/ip_country match'
89
133
  }
90
134
 
91
135
  # These are the options that can be used when creating a new CyberSource
@@ -114,7 +158,7 @@ module ActiveMerchant #:nodoc:
114
158
 
115
159
  def authorize(money, creditcard_or_reference, options = {})
116
160
  setup_address_hash(options)
117
- commit(build_auth_request(money, creditcard_or_reference, options), :authorize, money, options )
161
+ commit(build_auth_request(money, creditcard_or_reference, options), :authorize, money, options)
118
162
  end
119
163
 
120
164
  def capture(money, authorization, options = {})
@@ -122,7 +166,6 @@ module ActiveMerchant #:nodoc:
122
166
  commit(build_capture_request(money, authorization, options), :capture, money, options)
123
167
  end
124
168
 
125
- # options[:pinless_debit_card] => true # attempts to process as pinless debit card
126
169
  def purchase(money, payment_method_or_reference, options = {})
127
170
  setup_address_hash(options)
128
171
  commit(build_purchase_request(money, payment_method_or_reference, options), :purchase, money, options)
@@ -136,16 +179,22 @@ module ActiveMerchant #:nodoc:
136
179
  commit(build_refund_request(money, identification, options), :refund, money, options)
137
180
  end
138
181
 
182
+ def adjust(money, authorization, options = {})
183
+ commit(build_adjust_request(money, authorization, options), :adjust, money, options)
184
+ end
185
+
139
186
  def verify(payment, options = {})
187
+ amount = eligible_for_zero_auth?(payment, options) ? 0 : 100
140
188
  MultiResponse.run(:use_first_response) do |r|
141
- r.process { authorize(100, payment, options) }
142
- r.process(:ignore_result) { void(r.authorization, options) }
189
+ r.process { authorize(amount, payment, options) }
190
+ r.process(:ignore_result) { void(r.authorization, options) } unless amount == 0
143
191
  end
144
192
  end
145
193
 
146
- # Adds credit to a subscription (stand alone credit).
147
- def credit(money, reference, options = {})
148
- commit(build_credit_request(money, reference, options), :credit, money, options)
194
+ # Adds credit to a card or subscription (stand alone credit).
195
+ def credit(money, creditcard_or_reference, options = {})
196
+ setup_address_hash(options)
197
+ commit(build_credit_request(money, creditcard_or_reference, options), :credit, money, options)
149
198
  end
150
199
 
151
200
  # Stores a customer subscription/profile with type "on-demand".
@@ -202,17 +251,11 @@ module ActiveMerchant #:nodoc:
202
251
  # This functionality is only supported by this particular gateway may
203
252
  # be changed at any time
204
253
  def calculate_tax(creditcard, options)
205
- requires!(options, :line_items)
254
+ requires!(options, :line_items)
206
255
  setup_address_hash(options)
207
256
  commit(build_tax_calculation_request(creditcard, options), :calculate_tax, nil, options)
208
257
  end
209
258
 
210
- # Determines if a card can be used for Pinless Debit Card transactions
211
- def validate_pinless_debit_card(creditcard, options = {})
212
- requires!(options, :order_id)
213
- commit(build_validate_pinless_debit_request(creditcard,options), :validate_pinless_debit_card, nil, options)
214
- end
215
-
216
259
  def supports_scrubbing?
217
260
  true
218
261
  end
@@ -232,131 +275,209 @@ module ActiveMerchant #:nodoc:
232
275
  end
233
276
 
234
277
  def verify_credentials
235
- response = void("0")
236
- response.params["reasonCode"] == "102"
278
+ response = void('0')
279
+ response.params['reasonCode'] == '102'
237
280
  end
238
281
 
239
282
  private
240
283
 
241
- # Create all address hash key value pairs so that we still function if we
242
- # were only provided with one or two of them or even none
284
+ # Create all required address hash key value pairs
285
+ # If a value of nil is received, that value will be passed on to the gateway and will not be replaced with a default value
286
+ # Billing address fields received without an override value or with an empty string value will be replaced with the default_address values
243
287
  def setup_address_hash(options)
244
288
  default_address = {
245
- :address1 => 'Unspecified',
246
- :city => 'Unspecified',
247
- :state => 'NC',
248
- :zip => '00000',
249
- :country => 'US'
289
+ address1: 'Unspecified',
290
+ city: 'Unspecified',
291
+ state: 'NC',
292
+ zip: '00000',
293
+ country: 'US'
250
294
  }
251
- options[:billing_address] = options[:billing_address] || options[:address] || default_address
295
+
296
+ submitted_address = options[:billing_address] || options[:address] || default_address
297
+ options[:billing_address] = default_address.merge(submitted_address.symbolize_keys) { |_k, default, submitted| check_billing_field_value(default, submitted) }
252
298
  options[:shipping_address] = options[:shipping_address] || {}
253
299
  end
254
300
 
301
+ def check_billing_field_value(default, submitted)
302
+ if submitted.nil?
303
+ nil
304
+ elsif submitted.blank?
305
+ default
306
+ else
307
+ submitted
308
+ end
309
+ end
310
+
255
311
  def build_auth_request(money, creditcard_or_reference, options)
256
- xml = Builder::XmlMarkup.new :indent => 2
312
+ xml = Builder::XmlMarkup.new indent: 2
313
+ add_customer_id(xml, options)
257
314
  add_payment_method_or_subscription(xml, money, creditcard_or_reference, options)
315
+ add_other_tax(xml, options)
316
+ add_threeds_2_ucaf_data(xml, creditcard_or_reference, options)
258
317
  add_decision_manager_fields(xml, options)
259
318
  add_mdd_fields(xml, options)
260
319
  add_auth_service(xml, creditcard_or_reference, options)
261
320
  add_threeds_services(xml, options)
262
- add_payment_network_token(xml) if network_tokenization?(creditcard_or_reference)
263
321
  add_business_rules_data(xml, creditcard_or_reference, options)
322
+ add_airline_data(xml, options)
323
+ add_sales_slip_number(xml, options)
324
+ add_payment_network_token(xml) if network_tokenization?(creditcard_or_reference)
325
+ add_tax_management_indicator(xml, options)
326
+ add_stored_credential_subsequent_auth(xml, options)
327
+ add_issuer_additional_data(xml, options)
328
+ add_partner_solution_id(xml)
329
+ add_stored_credential_options(xml, options)
330
+ add_merchant_description(xml, options)
331
+ xml.target!
332
+ end
333
+
334
+ def build_adjust_request(money, authorization, options)
335
+ _, request_id = authorization.split(';')
336
+
337
+ xml = Builder::XmlMarkup.new indent: 2
338
+ add_purchase_data(xml, money, true, options)
339
+ add_incremental_auth_service(xml, request_id, options)
264
340
  xml.target!
265
341
  end
266
342
 
267
343
  def build_tax_calculation_request(creditcard, options)
268
- xml = Builder::XmlMarkup.new :indent => 2
344
+ xml = Builder::XmlMarkup.new indent: 2
269
345
  add_address(xml, creditcard, options[:billing_address], options, false)
270
346
  add_address(xml, creditcard, options[:shipping_address], options, true)
271
347
  add_line_item_data(xml, options)
272
348
  add_purchase_data(xml, 0, false, options)
273
349
  add_tax_service(xml)
274
350
  add_business_rules_data(xml, creditcard, options)
351
+ add_tax_management_indicator(xml, options)
275
352
  xml.target!
276
353
  end
277
354
 
278
355
  def build_capture_request(money, authorization, options)
279
- order_id, request_id, request_token = authorization.split(";")
356
+ order_id, request_id, request_token = authorization.split(';')
280
357
  options[:order_id] = order_id
281
358
 
282
- xml = Builder::XmlMarkup.new :indent => 2
359
+ xml = Builder::XmlMarkup.new indent: 2
283
360
  add_purchase_data(xml, money, true, options)
284
- add_capture_service(xml, request_id, request_token)
361
+ add_other_tax(xml, options)
362
+ add_mdd_fields(xml, options)
363
+ add_capture_service(xml, request_id, request_token, options)
285
364
  add_business_rules_data(xml, authorization, options)
365
+ add_tax_management_indicator(xml, options)
366
+ add_issuer_additional_data(xml, options)
367
+ add_merchant_description(xml, options)
368
+ add_partner_solution_id(xml)
369
+
286
370
  xml.target!
287
371
  end
288
372
 
289
373
  def build_purchase_request(money, payment_method_or_reference, options)
290
- xml = Builder::XmlMarkup.new :indent => 2
374
+ xml = Builder::XmlMarkup.new indent: 2
375
+ add_customer_id(xml, options)
291
376
  add_payment_method_or_subscription(xml, money, payment_method_or_reference, options)
377
+ add_other_tax(xml, options)
378
+ add_threeds_2_ucaf_data(xml, payment_method_or_reference, options)
292
379
  add_decision_manager_fields(xml, options)
293
380
  add_mdd_fields(xml, options)
294
- if !payment_method_or_reference.is_a?(String) && card_brand(payment_method_or_reference) == 'check'
381
+ if (!payment_method_or_reference.is_a?(String) && card_brand(payment_method_or_reference) == 'check') || reference_is_a_check?(payment_method_or_reference)
295
382
  add_check_service(xml)
383
+ add_airline_data(xml, options)
384
+ add_sales_slip_number(xml, options)
385
+ add_tax_management_indicator(xml, options)
386
+ add_issuer_additional_data(xml, options)
387
+ add_partner_solution_id(xml)
388
+ options[:payment_method] = :check
296
389
  else
297
390
  add_purchase_service(xml, payment_method_or_reference, options)
298
391
  add_threeds_services(xml, options)
392
+ add_business_rules_data(xml, payment_method_or_reference, options)
393
+ add_airline_data(xml, options)
394
+ add_sales_slip_number(xml, options)
299
395
  add_payment_network_token(xml) if network_tokenization?(payment_method_or_reference)
300
- add_business_rules_data(xml, payment_method_or_reference, options) unless options[:pinless_debit_card]
396
+ add_tax_management_indicator(xml, options)
397
+ add_stored_credential_subsequent_auth(xml, options)
398
+ add_issuer_additional_data(xml, options)
399
+ add_partner_solution_id(xml)
400
+ add_stored_credential_options(xml, options)
401
+ options[:payment_method] = :credit_card
301
402
  end
403
+
404
+ add_merchant_description(xml, options)
405
+
302
406
  xml.target!
303
407
  end
304
408
 
409
+ def reference_is_a_check?(payment_method_or_reference)
410
+ payment_method_or_reference.is_a?(String) && payment_method_or_reference.split(';')[7] == 'check'
411
+ end
412
+
305
413
  def build_void_request(identification, options)
306
- order_id, request_id, request_token, action, money, currency = identification.split(";")
414
+ order_id, request_id, request_token, action, money, currency = identification.split(';')
307
415
  options[:order_id] = order_id
308
416
 
309
- xml = Builder::XmlMarkup.new :indent => 2
310
- if action == "capture"
417
+ xml = Builder::XmlMarkup.new indent: 2
418
+ case action
419
+ when 'capture', 'purchase'
420
+ add_mdd_fields(xml, options)
311
421
  add_void_service(xml, request_id, request_token)
312
422
  else
313
- add_purchase_data(xml, money, true, options.merge(:currency => currency || default_currency))
423
+ add_purchase_data(xml, money, true, options.merge(currency: currency || default_currency))
424
+ add_mdd_fields(xml, options)
314
425
  add_auth_reversal_service(xml, request_id, request_token)
315
426
  end
427
+ add_issuer_additional_data(xml, options)
428
+ add_partner_solution_id(xml)
429
+
316
430
  xml.target!
317
431
  end
318
432
 
319
433
  def build_refund_request(money, identification, options)
320
- order_id, request_id, request_token = identification.split(";")
434
+ order_id, request_id, request_token = identification.split(';')
321
435
  options[:order_id] = order_id
322
436
 
323
- xml = Builder::XmlMarkup.new :indent => 2
437
+ xml = Builder::XmlMarkup.new indent: 2
324
438
  add_purchase_data(xml, money, true, options)
325
- add_credit_service(xml, request_id, request_token)
439
+ add_credit_service(xml, request_id: request_id,
440
+ request_token: request_token,
441
+ use_check_service: reference_is_a_check?(identification))
442
+ add_partner_solution_id(xml)
326
443
 
327
444
  xml.target!
328
445
  end
329
446
 
330
- def build_credit_request(money, reference, options)
331
- xml = Builder::XmlMarkup.new :indent => 2
447
+ def build_credit_request(money, creditcard_or_reference, options)
448
+ xml = Builder::XmlMarkup.new indent: 2
332
449
 
333
- add_purchase_data(xml, money, true, options)
334
- add_subscription(xml, options, reference)
335
- add_credit_service(xml)
450
+ add_payment_method_or_subscription(xml, money, creditcard_or_reference, options)
451
+ add_mdd_fields(xml, options)
452
+ add_credit_service(xml, use_check_service: creditcard_or_reference.is_a?(Check))
453
+ add_issuer_additional_data(xml, options)
454
+ add_merchant_description(xml, options)
336
455
 
337
456
  xml.target!
338
457
  end
339
458
 
340
459
  def build_create_subscription_request(payment_method, options)
341
- default_subscription_params = {:frequency => "on-demand", :amount => 0, :automatic_renew => false}
460
+ default_subscription_params = { frequency: 'on-demand', amount: 0, automatic_renew: false }
342
461
  options[:subscription] = default_subscription_params.update(
343
462
  options[:subscription] || {}
344
463
  )
345
464
 
346
- xml = Builder::XmlMarkup.new :indent => 2
465
+ xml = Builder::XmlMarkup.new indent: 2
347
466
  add_address(xml, payment_method, options[:billing_address], options)
348
467
  add_purchase_data(xml, options[:setup_fee] || 0, true, options)
349
468
  if card_brand(payment_method) == 'check'
350
- add_check(xml, payment_method)
469
+ add_check(xml, payment_method, options)
351
470
  add_check_payment_method(xml)
471
+ options[:payment_method] = :check
352
472
  else
353
473
  add_creditcard(xml, payment_method)
354
474
  add_creditcard_payment_method(xml)
475
+ options[:payment_method] = :credit_card
355
476
  end
356
477
  add_subscription(xml, options)
357
478
  if options[:setup_fee]
358
479
  if card_brand(payment_method) == 'check'
359
- add_check_service(xml, options)
480
+ add_check_service(xml)
360
481
  else
361
482
  add_purchase_service(xml, payment_method, options)
362
483
  add_payment_network_token(xml) if network_tokenization?(payment_method)
@@ -364,11 +485,12 @@ module ActiveMerchant #:nodoc:
364
485
  end
365
486
  add_subscription_create_service(xml, options)
366
487
  add_business_rules_data(xml, payment_method, options)
488
+ add_tax_management_indicator(xml, options)
367
489
  xml.target!
368
490
  end
369
491
 
370
492
  def build_update_subscription_request(reference, creditcard, options)
371
- xml = Builder::XmlMarkup.new :indent => 2
493
+ xml = Builder::XmlMarkup.new indent: 2
372
494
  add_address(xml, creditcard, options[:billing_address], options) unless options[:billing_address].blank?
373
495
  add_purchase_data(xml, options[:setup_fee], true, options) unless options[:setup_fee].blank?
374
496
  add_creditcard(xml, creditcard) if creditcard
@@ -376,42 +498,36 @@ module ActiveMerchant #:nodoc:
376
498
  add_subscription(xml, options, reference)
377
499
  add_subscription_update_service(xml, options)
378
500
  add_business_rules_data(xml, creditcard, options)
501
+ add_tax_management_indicator(xml, options)
379
502
  xml.target!
380
503
  end
381
504
 
382
505
  def build_delete_subscription_request(reference, options)
383
- xml = Builder::XmlMarkup.new :indent => 2
506
+ xml = Builder::XmlMarkup.new indent: 2
384
507
  add_subscription(xml, options, reference)
385
508
  add_subscription_delete_service(xml, options)
386
509
  xml.target!
387
510
  end
388
511
 
389
512
  def build_retrieve_subscription_request(reference, options)
390
- xml = Builder::XmlMarkup.new :indent => 2
513
+ xml = Builder::XmlMarkup.new indent: 2
391
514
  add_subscription(xml, options, reference)
392
515
  add_subscription_retrieve_service(xml, options)
393
516
  xml.target!
394
517
  end
395
518
 
396
- def build_validate_pinless_debit_request(creditcard,options)
397
- xml = Builder::XmlMarkup.new :indent => 2
398
- add_creditcard(xml, creditcard)
399
- add_validate_pinless_debit_service(xml)
400
- xml.target!
401
- end
402
-
403
519
  def add_business_rules_data(xml, payment_method, options)
404
520
  prioritized_options = [options, @options]
405
521
 
406
522
  unless network_tokenization?(payment_method)
407
523
  xml.tag! 'businessRules' do
408
- xml.tag!('ignoreAVSResult', 'true') if extract_option(prioritized_options, :ignore_avs)
409
- xml.tag!('ignoreCVResult', 'true') if extract_option(prioritized_options, :ignore_cvv)
524
+ xml.tag!('ignoreAVSResult', 'true') if extract_option(prioritized_options, :ignore_avs).to_s == 'true'
525
+ xml.tag!('ignoreCVResult', 'true') if extract_option(prioritized_options, :ignore_cvv).to_s == 'true'
410
526
  end
411
527
  end
412
528
  end
413
529
 
414
- def extract_option prioritized_options, option_name
530
+ def extract_option(prioritized_options, option_name)
415
531
  options_matching_key = prioritized_options.detect do |options|
416
532
  options.has_key? option_name
417
533
  end
@@ -419,13 +535,17 @@ module ActiveMerchant #:nodoc:
419
535
  end
420
536
 
421
537
  def add_line_item_data(xml, options)
538
+ return unless options[:line_items]
539
+
422
540
  options[:line_items].each_with_index do |value, index|
423
- xml.tag! 'item', {'id' => index} do
541
+ xml.tag! 'item', { 'id' => index } do
424
542
  xml.tag! 'unitPrice', localized_amount(value[:declared_value].to_i, options[:currency] || default_currency)
425
543
  xml.tag! 'quantity', value[:quantity]
426
544
  xml.tag! 'productCode', value[:code] || 'shipping_only'
427
545
  xml.tag! 'productName', value[:description]
428
546
  xml.tag! 'productSKU', value[:sku]
547
+ xml.tag! 'taxAmount', value[:tax_amount] if value[:tax_amount]
548
+ xml.tag! 'nationalTax', value[:national_tax] if value[:national_tax]
429
549
  end
430
550
  end
431
551
  end
@@ -433,24 +553,81 @@ module ActiveMerchant #:nodoc:
433
553
  def add_merchant_data(xml, options)
434
554
  xml.tag! 'merchantID', @options[:login]
435
555
  xml.tag! 'merchantReferenceCode', options[:order_id] || generate_unique_id
436
- xml.tag! 'clientLibrary' ,'Ruby Active Merchant'
437
- xml.tag! 'clientLibraryVersion', VERSION
438
- xml.tag! 'clientEnvironment' , RUBY_PLATFORM
556
+ xml.tag! 'clientLibrary', 'Ruby Active Merchant'
557
+ xml.tag! 'clientLibraryVersion', VERSION
558
+ xml.tag! 'clientEnvironment', RUBY_PLATFORM
559
+
560
+ add_merchant_descriptor(xml, options)
561
+ end
562
+
563
+ def add_merchant_descriptor(xml, options)
564
+ return unless options[:merchant_descriptor] || options[:user_po] || options[:taxable] || options[:reference_data_code] || options[:invoice_number]
565
+
566
+ xml.tag! 'invoiceHeader' do
567
+ xml.tag! 'merchantDescriptor', options[:merchant_descriptor] if options[:merchant_descriptor]
568
+ xml.tag! 'userPO', options[:user_po] if options[:user_po]
569
+ xml.tag! 'taxable', options[:taxable] if options[:taxable]
570
+ xml.tag! 'referenceDataCode', options[:reference_data_code] if options[:reference_data_code]
571
+ xml.tag! 'invoiceNumber', options[:invoice_number] if options[:invoice_number]
572
+ end
573
+ end
574
+
575
+ def add_customer_id(xml, options)
576
+ return unless options[:customer_id]
577
+
578
+ xml.tag! 'customerID', options[:customer_id]
579
+ end
580
+
581
+ def add_merchant_description(xml, options)
582
+ return unless options[:merchant_descriptor_name] || options[:merchant_descriptor_address1] || options[:merchant_descriptor_locality]
583
+
584
+ xml.tag! 'merchantInformation' do
585
+ xml.tag! 'merchantDescriptor' do
586
+ xml.tag! 'name', options[:merchant_descriptor_name] if options[:merchant_descriptor_name]
587
+ xml.tag! 'address1', options[:merchant_descriptor_address1] if options[:merchant_descriptor_address1]
588
+ xml.tag! 'locality', options[:merchant_descriptor_locality] if options[:merchant_descriptor_locality]
589
+ end
590
+ end
591
+ end
592
+
593
+ def add_sales_slip_number(xml, options)
594
+ xml.tag! 'salesSlipNumber', options[:sales_slip_number] if options[:sales_slip_number]
439
595
  end
440
596
 
441
- def add_purchase_data(xml, money = 0, include_grand_total = false, options={})
597
+ def add_airline_data(xml, options)
598
+ return unless options[:airline_agent_code]
599
+
600
+ xml.tag! 'airlineData' do
601
+ xml.tag! 'agentCode', options[:airline_agent_code]
602
+ end
603
+ end
604
+
605
+ def add_tax_management_indicator(xml, options)
606
+ return unless options[:tax_management_indicator]
607
+
608
+ xml.tag! 'taxManagementIndicator', options[:tax_management_indicator] if options[:tax_management_indicator]
609
+ end
610
+
611
+ def add_purchase_data(xml, money = 0, include_grand_total = false, options = {})
442
612
  xml.tag! 'purchaseTotals' do
443
613
  xml.tag! 'currency', options[:currency] || currency(money)
444
- xml.tag!('grandTotalAmount', localized_amount(money.to_i, options[:currency] || default_currency)) if include_grand_total
614
+ xml.tag!('discountManagementIndicator', options[:discount_management_indicator]) if options[:discount_management_indicator]
615
+ xml.tag!('taxAmount', options[:purchase_tax_amount]) if options[:purchase_tax_amount]
616
+ xml.tag!('grandTotalAmount', localized_amount(money.to_i, options[:currency] || default_currency)) if include_grand_total
617
+ xml.tag!('originalAmount', options[:original_amount]) if options[:original_amount]
618
+ xml.tag!('invoiceAmount', options[:invoice_amount]) if options[:invoice_amount]
445
619
  end
446
620
  end
447
621
 
448
622
  def add_address(xml, payment_method, address, options, shipTo = false)
623
+ first_name, last_name = address_names(address[:name], payment_method)
624
+ bill_to_merchant_tax_id = options[:merchant_tax_id] unless shipTo
625
+
449
626
  xml.tag! shipTo ? 'shipTo' : 'billTo' do
450
- xml.tag! 'firstName', payment_method.first_name if payment_method
451
- xml.tag! 'lastName', payment_method.last_name if payment_method
627
+ xml.tag! 'firstName', first_name if first_name
628
+ xml.tag! 'lastName', last_name if last_name
452
629
  xml.tag! 'street1', address[:address1]
453
- xml.tag! 'street2', address[:address2] unless address[:address2].blank?
630
+ xml.tag! 'street2', address[:address2] unless address[:address2].blank?
454
631
  xml.tag! 'city', address[:city]
455
632
  xml.tag! 'state', address[:state]
456
633
  xml.tag! 'postalCode', address[:zip]
@@ -458,19 +635,30 @@ module ActiveMerchant #:nodoc:
458
635
  xml.tag! 'company', address[:company] unless address[:company].blank?
459
636
  xml.tag! 'companyTaxID', address[:companyTaxID] unless address[:company_tax_id].blank?
460
637
  xml.tag! 'phoneNumber', address[:phone] unless address[:phone].blank?
461
- xml.tag! 'email', options[:email] || 'null@cybersource.com'
638
+ xml.tag! 'email', options[:email].presence || 'null@cybersource.com'
462
639
  xml.tag! 'ipAddress', options[:ip] unless options[:ip].blank? || shipTo
463
640
  xml.tag! 'driversLicenseNumber', options[:drivers_license_number] unless options[:drivers_license_number].blank?
464
641
  xml.tag! 'driversLicenseState', options[:drivers_license_state] unless options[:drivers_license_state].blank?
642
+ xml.tag! 'merchantTaxID', bill_to_merchant_tax_id unless bill_to_merchant_tax_id.blank?
465
643
  end
466
644
  end
467
645
 
646
+ def address_names(address_name, payment_method)
647
+ names = split_names(address_name)
648
+ return names if names.any?(&:present?)
649
+
650
+ [
651
+ payment_method&.first_name,
652
+ payment_method&.last_name
653
+ ]
654
+ end
655
+
468
656
  def add_creditcard(xml, creditcard)
469
657
  xml.tag! 'card' do
470
658
  xml.tag! 'accountNumber', creditcard.number
471
659
  xml.tag! 'expirationMonth', format(creditcard.month, :two_digits)
472
660
  xml.tag! 'expirationYear', format(creditcard.year, :four_digits)
473
- xml.tag!('cvNumber', creditcard.verification_value) unless (@options[:ignore_cvv] || creditcard.verification_value.blank? )
661
+ xml.tag!('cvNumber', creditcard.verification_value) unless @options[:ignore_cvv].to_s == 'true' || creditcard.verification_value.blank?
474
662
  xml.tag! 'cardType', @@credit_card_codes[card_brand(creditcard).to_sym]
475
663
  end
476
664
  end
@@ -484,27 +672,47 @@ module ActiveMerchant #:nodoc:
484
672
  end
485
673
  end
486
674
 
675
+ def add_issuer_additional_data(xml, options)
676
+ return unless options[:issuer_additional_data]
677
+
678
+ xml.tag! 'issuer' do
679
+ xml.tag! 'additionalData', options[:issuer_additional_data]
680
+ end
681
+ end
682
+
683
+ def add_other_tax(xml, options)
684
+ return unless options[:local_tax_amount] || options[:national_tax_amount] || options[:national_tax_indicator]
685
+
686
+ xml.tag! 'otherTax' do
687
+ xml.tag! 'vatTaxRate', options[:vat_tax_rate] if options[:vat_tax_rate]
688
+ xml.tag! 'localTaxAmount', options[:local_tax_amount] if options[:local_tax_amount]
689
+ xml.tag! 'nationalTaxAmount', options[:national_tax_amount] if options[:national_tax_amount]
690
+ xml.tag! 'nationalTaxIndicator', options[:national_tax_indicator] if options[:national_tax_indicator]
691
+ end
692
+ end
693
+
487
694
  def add_mdd_fields(xml, options)
488
- return unless options.keys.any? { |key| key.to_s.start_with?("mdd_field") }
695
+ return unless options.keys.any? { |key| key.to_s.start_with?('mdd_field') && options[key] }
489
696
 
490
697
  xml.tag! 'merchantDefinedData' do
491
698
  (1..100).each do |each|
492
699
  key = "mdd_field_#{each}".to_sym
493
- xml.tag!("field#{each}", options[key]) if options[key]
700
+ xml.tag!('mddField', options[key], 'id' => each) if options[key]
494
701
  end
495
702
  end
496
703
  end
497
704
 
498
- def add_check(xml, check)
705
+ def add_check(xml, check, options)
499
706
  xml.tag! 'check' do
500
707
  xml.tag! 'accountNumber', check.account_number
501
708
  xml.tag! 'accountType', check.account_type[0]
502
709
  xml.tag! 'bankTransitNumber', check.routing_number
710
+ xml.tag! 'secCode', options[:sec_code] if options[:sec_code]
503
711
  end
504
712
  end
505
713
 
506
714
  def add_tax_service(xml)
507
- xml.tag! 'taxService', {'run' => 'true'} do
715
+ xml.tag! 'taxService', { 'run' => 'true' } do
508
716
  xml.tag!('nexus', @options[:nexus]) unless @options[:nexus].blank?
509
717
  xml.tag!('sellerRegistration', @options[:vat_reg_number]) unless @options[:vat_reg_number].blank?
510
718
  end
@@ -514,7 +722,73 @@ module ActiveMerchant #:nodoc:
514
722
  if network_tokenization?(payment_method)
515
723
  add_auth_network_tokenization(xml, payment_method, options)
516
724
  else
517
- xml.tag! 'ccAuthService', {'run' => 'true'}
725
+ xml.tag! 'ccAuthService', { 'run' => 'true' } do
726
+ if options[:three_d_secure]
727
+ add_normalized_threeds_2_data(xml, payment_method, options)
728
+ else
729
+ indicator = options[:commerce_indicator] || stored_credential_commerce_indicator(options)
730
+ xml.tag!('commerceIndicator', indicator) if indicator
731
+ end
732
+ xml.tag!('reconciliationID', options[:reconciliation_id]) if options[:reconciliation_id]
733
+ xml.tag!('mobileRemotePaymentType', options[:mobile_remote_payment_type]) if options[:mobile_remote_payment_type]
734
+ end
735
+ end
736
+ end
737
+
738
+ def add_incremental_auth_service(xml, authorization, options)
739
+ xml.tag! 'ccIncrementalAuthService', { 'run' => 'true' } do
740
+ xml.tag! 'authRequestID', authorization
741
+ end
742
+ xml.tag! 'subsequentAuthReason', options[:auth_reason]
743
+ end
744
+
745
+ def add_normalized_threeds_2_data(xml, payment_method, options)
746
+ threeds_2_options = options[:three_d_secure]
747
+ cc_brand = card_brand(payment_method).to_sym
748
+
749
+ return if threeds_2_options[:cavv].blank? && infer_commerce_indicator?(options, cc_brand)
750
+
751
+ xid = threeds_2_options[:xid]
752
+
753
+ xml.tag!('cavv', threeds_2_options[:cavv]) if threeds_2_options[:cavv] && cc_brand != :master
754
+ xml.tag!('cavvAlgorithm', threeds_2_options[:cavv_algorithm]) if threeds_2_options[:cavv_algorithm]
755
+ xml.tag!('paSpecificationVersion', threeds_2_options[:version]) if threeds_2_options[:version]
756
+ xml.tag!('directoryServerTransactionID', threeds_2_options[:ds_transaction_id]) if threeds_2_options[:ds_transaction_id]
757
+ xml.tag!('commerceIndicator', options[:commerce_indicator] || ECI_BRAND_MAPPING[cc_brand])
758
+ xml.tag!('eciRaw', threeds_2_options[:eci]) if threeds_2_options[:eci]
759
+
760
+ if xid.present?
761
+ xml.tag!('xid', xid)
762
+ elsif threeds_2_options[:version]&.start_with?('2') && cc_brand != :master
763
+ cavv = threeds_2_options[:cavv]
764
+ xml.tag!('xid', cavv) if cavv.present?
765
+ end
766
+
767
+ xml.tag!('veresEnrolled', threeds_2_options[:enrolled]) if threeds_2_options[:enrolled]
768
+ xml.tag!('paresStatus', threeds_2_options[:authentication_response_status]) if threeds_2_options[:authentication_response_status]
769
+ end
770
+
771
+ def infer_commerce_indicator?(options, cc_brand)
772
+ options[:commerce_indicator].blank? && ECI_BRAND_MAPPING[cc_brand].present?
773
+ end
774
+
775
+ def add_threeds_2_ucaf_data(xml, payment_method, options)
776
+ return unless options[:three_d_secure] && card_brand(payment_method).to_sym == :master
777
+
778
+ xml.tag! 'ucaf' do
779
+ xml.tag!('authenticationData', options[:three_d_secure][:cavv])
780
+ xml.tag!('collectionIndicator', options[:collection_indicator] || DEFAULT_COLLECTION_INDICATOR)
781
+ end
782
+ end
783
+
784
+ def stored_credential_commerce_indicator(options)
785
+ return unless options[:stored_credential]
786
+
787
+ return if options[:stored_credential][:initial_transaction]
788
+
789
+ case options[:stored_credential][:reason_type]
790
+ when 'installment' then 'install'
791
+ when 'recurring' then 'recurring'
518
792
  end
519
793
  end
520
794
 
@@ -525,28 +799,35 @@ module ActiveMerchant #:nodoc:
525
799
  def add_auth_network_tokenization(xml, payment_method, options)
526
800
  return unless network_tokenization?(payment_method)
527
801
 
528
- case card_brand(payment_method).to_sym
802
+ brand = card_brand(payment_method).to_sym
803
+
804
+ case brand
529
805
  when :visa
530
- xml.tag! 'ccAuthService', {'run' => 'true'} do
531
- xml.tag!("cavv", payment_method.payment_cryptogram)
532
- xml.tag!("commerceIndicator", "vbv")
533
- xml.tag!("xid", payment_method.payment_cryptogram)
806
+ xml.tag! 'ccAuthService', { 'run' => 'true' } do
807
+ xml.tag!('cavv', payment_method.payment_cryptogram)
808
+ xml.tag!('commerceIndicator', ECI_BRAND_MAPPING[brand])
809
+ xml.tag!('xid', payment_method.payment_cryptogram)
810
+ xml.tag!('reconciliationID', options[:reconciliation_id]) if options[:reconciliation_id]
534
811
  end
535
- when :mastercard
812
+ when :master
536
813
  xml.tag! 'ucaf' do
537
- xml.tag!("authenticationData", payment_method.payment_cryptogram)
538
- xml.tag!("collectionIndicator", "2")
814
+ xml.tag!('authenticationData', payment_method.payment_cryptogram)
815
+ xml.tag!('collectionIndicator', DEFAULT_COLLECTION_INDICATOR)
539
816
  end
540
- xml.tag! 'ccAuthService', {'run' => 'true'} do
541
- xml.tag!("commerceIndicator", "spa")
817
+ xml.tag! 'ccAuthService', { 'run' => 'true' } do
818
+ xml.tag!('commerceIndicator', ECI_BRAND_MAPPING[brand])
819
+ xml.tag!('reconciliationID', options[:reconciliation_id]) if options[:reconciliation_id]
542
820
  end
543
821
  when :american_express
544
822
  cryptogram = Base64.decode64(payment_method.payment_cryptogram)
545
- xml.tag! 'ccAuthService', {'run' => 'true'} do
546
- xml.tag!("cavv", Base64.encode64(cryptogram[0...20]))
547
- xml.tag!("commerceIndicator", "aesk")
548
- xml.tag!("xid", Base64.encode64(cryptogram[20...40]))
823
+ xml.tag! 'ccAuthService', { 'run' => 'true' } do
824
+ xml.tag!('cavv', Base64.encode64(cryptogram[0...20]))
825
+ xml.tag!('commerceIndicator', ECI_BRAND_MAPPING[brand])
826
+ xml.tag!('xid', Base64.encode64(cryptogram[20...40])) if cryptogram.bytes.count > 20
827
+ xml.tag!('reconciliationID', options[:reconciliation_id]) if options[:reconciliation_id]
549
828
  end
829
+ else
830
+ raise ArgumentError.new("Payment method #{brand} is not supported, check https://developer.cybersource.com/docs/cybs/en-us/payments/developer/all/rest/payments/CreatingOnlineAuth/CreatingAuthReqPNT.html")
550
831
  end
551
832
  end
552
833
 
@@ -556,61 +837,65 @@ module ActiveMerchant #:nodoc:
556
837
  end
557
838
  end
558
839
 
559
- def add_capture_service(xml, request_id, request_token)
560
- xml.tag! 'ccCaptureService', {'run' => 'true'} do
840
+ def add_capture_service(xml, request_id, request_token, options)
841
+ xml.tag! 'ccCaptureService', { 'run' => 'true' } do
561
842
  xml.tag! 'authRequestID', request_id
562
843
  xml.tag! 'authRequestToken', request_token
844
+ xml.tag! 'gratuityAmount', options[:gratuity_amount] if options[:gratuity_amount]
845
+ xml.tag! 'reconciliationID', options[:reconciliation_id] if options[:reconciliation_id]
563
846
  end
564
847
  end
565
848
 
566
849
  def add_purchase_service(xml, payment_method, options)
567
- if options[:pinless_debit_card]
568
- xml.tag! 'pinlessDebitService', {'run' => 'true'}
569
- else
570
- add_auth_service(xml, payment_method, options)
571
- xml.tag! 'ccCaptureService', {'run' => 'true'}
850
+ add_auth_service(xml, payment_method, options)
851
+ xml.tag! 'ccCaptureService', { 'run' => 'true' } do
852
+ xml.tag!('reconciliationID', options[:reconciliation_id]) if options[:reconciliation_id]
572
853
  end
573
854
  end
574
855
 
575
856
  def add_void_service(xml, request_id, request_token)
576
- xml.tag! 'voidService', {'run' => 'true'} do
857
+ xml.tag! 'voidService', { 'run' => 'true' } do
577
858
  xml.tag! 'voidRequestID', request_id
578
859
  xml.tag! 'voidRequestToken', request_token
579
860
  end
580
861
  end
581
862
 
582
863
  def add_auth_reversal_service(xml, request_id, request_token)
583
- xml.tag! 'ccAuthReversalService', {'run' => 'true'} do
864
+ xml.tag! 'ccAuthReversalService', { 'run' => 'true' } do
584
865
  xml.tag! 'authRequestID', request_id
585
866
  xml.tag! 'authRequestToken', request_token
586
867
  end
587
868
  end
588
869
 
589
- def add_credit_service(xml, request_id = nil, request_token = nil)
590
- xml.tag! 'ccCreditService', {'run' => 'true'} do
591
- xml.tag! 'captureRequestID', request_id if request_id
592
- xml.tag! 'captureRequestToken', request_token if request_token
870
+ def add_credit_service(xml, options = {})
871
+ service = options[:use_check_service] ? 'ecCreditService' : 'ccCreditService'
872
+ request_tag = options[:use_check_service] ? 'debitRequestID' : 'captureRequestID'
873
+ options.delete :request_token if options[:use_check_service]
874
+
875
+ xml.tag! service, { 'run' => 'true' } do
876
+ xml.tag! request_tag, options[:request_id] if options[:request_id]
877
+ xml.tag! 'captureRequestToken', options[:request_token] if options[:request_token]
593
878
  end
594
879
  end
595
880
 
596
881
  def add_check_service(xml)
597
- xml.tag! 'ecDebitService', {'run' => 'true'}
882
+ xml.tag! 'ecDebitService', { 'run' => 'true' }
598
883
  end
599
884
 
600
885
  def add_subscription_create_service(xml, options)
601
- xml.tag! 'paySubscriptionCreateService', {'run' => 'true'}
886
+ xml.tag! 'paySubscriptionCreateService', { 'run' => 'true' }
602
887
  end
603
888
 
604
889
  def add_subscription_update_service(xml, options)
605
- xml.tag! 'paySubscriptionUpdateService', {'run' => 'true'}
890
+ xml.tag! 'paySubscriptionUpdateService', { 'run' => 'true' }
606
891
  end
607
892
 
608
893
  def add_subscription_delete_service(xml, options)
609
- xml.tag! 'paySubscriptionDeleteService', {'run' => 'true'}
894
+ xml.tag! 'paySubscriptionDeleteService', { 'run' => 'true' }
610
895
  end
611
896
 
612
897
  def add_subscription_retrieve_service(xml, options)
613
- xml.tag! 'paySubscriptionRetrieveService', {'run' => 'true'}
898
+ xml.tag! 'paySubscriptionRetrieveService', { 'run' => 'true' }
614
899
  end
615
900
 
616
901
  def add_subscription(xml, options, reference = nil)
@@ -618,17 +903,17 @@ module ActiveMerchant #:nodoc:
618
903
 
619
904
  xml.tag! 'recurringSubscriptionInfo' do
620
905
  if reference
621
- subscription_id = reference.split(";")[6]
906
+ subscription_id = reference.split(';')[6]
622
907
  xml.tag! 'subscriptionID', subscription_id
623
908
  end
624
909
 
625
- xml.tag! 'status', options[:subscription][:status] if options[:subscription][:status]
910
+ xml.tag! 'status', options[:subscription][:status] if options[:subscription][:status]
626
911
  xml.tag! 'amount', localized_amount(options[:subscription][:amount].to_i, options[:currency] || default_currency) if options[:subscription][:amount]
627
912
  xml.tag! 'numberOfPayments', options[:subscription][:occurrences] if options[:subscription][:occurrences]
628
913
  xml.tag! 'automaticRenew', options[:subscription][:automatic_renew] if options[:subscription][:automatic_renew]
629
914
  xml.tag! 'frequency', options[:subscription][:frequency] if options[:subscription][:frequency]
630
- xml.tag! 'startDate', options[:subscription][:start_date].strftime("%Y%m%d") if options[:subscription][:start_date]
631
- xml.tag! 'endDate', options[:subscription][:end_date].strftime("%Y%m%d") if options[:subscription][:end_date]
915
+ xml.tag! 'startDate', options[:subscription][:start_date].strftime('%Y%m%d') if options[:subscription][:start_date]
916
+ xml.tag! 'endDate', options[:subscription][:end_date].strftime('%Y%m%d') if options[:subscription][:end_date]
632
917
  xml.tag! 'approvalRequired', options[:subscription][:approval_required] || false
633
918
  xml.tag! 'event', options[:subscription][:event] if options[:subscription][:event]
634
919
  xml.tag! 'billPayment', options[:subscription][:bill_payment] if options[:subscription][:bill_payment]
@@ -637,40 +922,53 @@ module ActiveMerchant #:nodoc:
637
922
 
638
923
  def add_creditcard_payment_method(xml)
639
924
  xml.tag! 'subscription' do
640
- xml.tag! 'paymentMethod', "credit card"
925
+ xml.tag! 'paymentMethod', 'credit card'
641
926
  end
642
927
  end
643
928
 
644
929
  def add_check_payment_method(xml)
645
930
  xml.tag! 'subscription' do
646
- xml.tag! 'paymentMethod', "check"
931
+ xml.tag! 'paymentMethod', 'check'
647
932
  end
648
933
  end
649
934
 
650
935
  def add_payment_method_or_subscription(xml, money, payment_method_or_reference, options)
651
936
  if payment_method_or_reference.is_a?(String)
652
937
  add_purchase_data(xml, money, true, options)
938
+ add_installments(xml, options)
653
939
  add_subscription(xml, options, payment_method_or_reference)
654
940
  elsif card_brand(payment_method_or_reference) == 'check'
655
941
  add_address(xml, payment_method_or_reference, options[:billing_address], options)
656
942
  add_purchase_data(xml, money, true, options)
657
- add_check(xml, payment_method_or_reference)
943
+ add_installments(xml, options)
944
+ add_check(xml, payment_method_or_reference, options)
658
945
  else
659
946
  add_address(xml, payment_method_or_reference, options[:billing_address], options)
660
947
  add_address(xml, payment_method_or_reference, options[:shipping_address], options, true)
948
+ add_line_item_data(xml, options)
661
949
  add_purchase_data(xml, money, true, options)
950
+ add_installments(xml, options)
662
951
  add_creditcard(xml, payment_method_or_reference)
663
952
  end
664
953
  end
665
954
 
666
- def add_validate_pinless_debit_service(xml)
667
- xml.tag!'pinlessDebitValidateService', {'run' => 'true'}
955
+ def add_installments(xml, options)
956
+ return unless %i[installment_total_count installment_total_amount installment_plan_type first_installment_date installment_annual_interest_rate installment_grace_period_duration].any? { |gsf| options.include?(gsf) }
957
+
958
+ xml.tag! 'installment' do
959
+ xml.tag!('totalCount', options[:installment_total_count]) if options[:installment_total_count]
960
+ xml.tag!('totalAmount', options[:installment_total_amount]) if options[:installment_total_amount]
961
+ xml.tag!('planType', options[:installment_plan_type]) if options[:installment_plan_type]
962
+ xml.tag!('firstInstallmentDate', options[:first_installment_date]) if options[:first_installment_date]
963
+ xml.tag!('annualInterestRate', options[:installment_annual_interest_rate]) if options[:installment_annual_interest_rate]
964
+ xml.tag!('gracePeriodDuration', options[:installment_grace_period_duration]) if options[:installment_grace_period_duration]
965
+ end
668
966
  end
669
967
 
670
968
  def add_threeds_services(xml, options)
671
- xml.tag! 'payerAuthEnrollService', {'run' => 'true'} if options[:payer_auth_enroll_service]
969
+ xml.tag! 'payerAuthEnrollService', { 'run' => 'true' } if options[:payer_auth_enroll_service]
672
970
  if options[:payer_auth_validate_service]
673
- xml.tag! 'payerAuthValidateService', {'run' => 'true'} do
971
+ xml.tag! 'payerAuthValidateService', { 'run' => 'true' } do
674
972
  xml.tag! 'signedPARes', options[:pares]
675
973
  end
676
974
  end
@@ -678,29 +976,63 @@ module ActiveMerchant #:nodoc:
678
976
 
679
977
  def lookup_country_code(country_field)
680
978
  country_code = Country.find(country_field) rescue nil
681
- country_code.code(:alpha2) if country_code
979
+ country_code&.code(:alpha2)
980
+ end
981
+
982
+ def add_stored_credential_subsequent_auth(xml, options = {})
983
+ return unless options[:stored_credential] || options[:stored_credential_overrides]
984
+
985
+ stored_credential_subsequent_auth = 'true' if options.dig(:stored_credential, :initiator) == 'merchant'
986
+
987
+ override_subsequent_auth = options.dig(:stored_credential_overrides, :subsequent_auth)
988
+
989
+ xml.subsequentAuth override_subsequent_auth.nil? ? stored_credential_subsequent_auth : override_subsequent_auth
990
+ end
991
+
992
+ def add_stored_credential_options(xml, options = {})
993
+ return unless options[:stored_credential] || options[:stored_credential_overrides]
994
+
995
+ stored_credential_subsequent_auth_first = 'true' if options.dig(:stored_credential, :initial_transaction)
996
+ stored_credential_transaction_id = options.dig(:stored_credential, :network_transaction_id) if options.dig(:stored_credential, :initiator) == 'merchant'
997
+ stored_credential_subsequent_auth_stored_cred = 'true' if options.dig(:stored_credential, :initiator) == 'cardholder' && !options.dig(:stored_credential, :initial_transaction) || options.dig(:stored_credential, :initiator) == 'merchant' && options.dig(:stored_credential, :reason_type) == 'unscheduled'
998
+
999
+ override_subsequent_auth_first = options.dig(:stored_credential_overrides, :subsequent_auth_first)
1000
+ override_subsequent_auth_transaction_id = options.dig(:stored_credential_overrides, :subsequent_auth_transaction_id)
1001
+ override_subsequent_auth_stored_cred = options.dig(:stored_credential_overrides, :subsequent_auth_stored_credential)
1002
+
1003
+ xml.subsequentAuthFirst override_subsequent_auth_first.nil? ? stored_credential_subsequent_auth_first : override_subsequent_auth_first
1004
+ xml.subsequentAuthTransactionID override_subsequent_auth_transaction_id.nil? ? stored_credential_transaction_id : override_subsequent_auth_transaction_id
1005
+ xml.subsequentAuthStoredCredential override_subsequent_auth_stored_cred.nil? ? stored_credential_subsequent_auth_stored_cred : override_subsequent_auth_stored_cred
1006
+ end
1007
+
1008
+ def add_partner_solution_id(xml)
1009
+ return unless application_id
1010
+
1011
+ xml.tag!('partnerSolutionID', application_id)
682
1012
  end
683
1013
 
684
1014
  # Where we actually build the full SOAP request using builder
685
1015
  def build_request(body, options)
686
- xml = Builder::XmlMarkup.new :indent => 2
687
- xml.instruct!
688
- xml.tag! 's:Envelope', {'xmlns:s' => 'http://schemas.xmlsoap.org/soap/envelope/'} do
689
- xml.tag! 's:Header' do
690
- xml.tag! 'wsse:Security', {'s:mustUnderstand' => '1', 'xmlns:wsse' => 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd'} do
691
- xml.tag! 'wsse:UsernameToken' do
692
- xml.tag! 'wsse:Username', @options[:login]
693
- xml.tag! 'wsse:Password', @options[:password], 'Type' => 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText'
694
- end
1016
+ xsd_version = test? ? TEST_XSD_VERSION : PRODUCTION_XSD_VERSION
1017
+
1018
+ xml = Builder::XmlMarkup.new indent: 2
1019
+ xml.instruct!
1020
+ xml.tag! 's:Envelope', { 'xmlns:s' => 'http://schemas.xmlsoap.org/soap/envelope/' } do
1021
+ xml.tag! 's:Header' do
1022
+ xml.tag! 'wsse:Security', { 's:mustUnderstand' => '1', 'xmlns:wsse' => 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd' } do
1023
+ xml.tag! 'wsse:UsernameToken' do
1024
+ xml.tag! 'wsse:Username', @options[:login]
1025
+ xml.tag! 'wsse:Password', @options[:password], 'Type' => 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText'
695
1026
  end
696
1027
  end
697
- xml.tag! 's:Body', {'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', 'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema'} do
698
- xml.tag! 'requestMessage', {'xmlns' => "urn:schemas-cybersource-com:transaction-data-#{XSD_VERSION}"} do
699
- add_merchant_data(xml, options)
700
- xml << body
701
- end
1028
+ end
1029
+ xml.tag! 's:Body', { 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', 'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema' } do
1030
+ xml.tag! 'requestMessage', { 'xmlns' => "urn:schemas-cybersource-com:transaction-data-#{xsd_version}" } do
1031
+ add_merchant_data(xml, options)
1032
+ xml << body
702
1033
  end
703
1034
  end
1035
+ end
704
1036
  xml.target!
705
1037
  end
706
1038
 
@@ -708,24 +1040,27 @@ module ActiveMerchant #:nodoc:
708
1040
  # Response object
709
1041
  def commit(request, action, amount, options)
710
1042
  begin
711
- response = parse(ssl_post(test? ? self.test_url : self.live_url, build_request(request, options)))
1043
+ raw_response = ssl_post(test? ? self.test_url : self.live_url, build_request(request, options))
712
1044
  rescue ResponseError => e
713
- response = parse(e.response.body)
1045
+ raw_response = e.response.body
1046
+ end
1047
+
1048
+ begin
1049
+ response = parse(raw_response)
714
1050
  rescue REXML::ParseException => e
715
1051
  response = { message: e.to_s }
716
1052
  end
717
1053
 
718
- success = response[:decision] == "ACCEPT"
719
- message = response[:message]
720
-
721
- authorization = success ? authorization_from(response, action, amount, options) : nil
1054
+ success = success?(response)
1055
+ message = message_from(response)
1056
+ authorization = success || in_fraud_review?(response) ? authorization_from(response, action, amount, options) : nil
722
1057
 
723
1058
  Response.new(success, message, response,
724
- :test => test?,
725
- :authorization => authorization,
726
- :avs_result => { :code => response[:avsCode] },
727
- :cvv_result => response[:cvCode]
728
- )
1059
+ test: test?,
1060
+ authorization: authorization,
1061
+ fraud_review: in_fraud_review?(response),
1062
+ avs_result: { code: response[:avsCode] },
1063
+ cvv_result: response[:cvCode])
729
1064
  end
730
1065
 
731
1066
  # Parse the SOAP response
@@ -733,7 +1068,7 @@ module ActiveMerchant #:nodoc:
733
1068
  def parse(xml)
734
1069
  reply = {}
735
1070
  xml = REXML::Document.new(xml)
736
- if root = REXML::XPath.first(xml, "//c:replyMessage")
1071
+ if root = REXML::XPath.first(xml, '//c:replyMessage')
737
1072
  root.elements.to_a.each do |node|
738
1073
  case node.expanded_name
739
1074
  when 'c:reasonCode'
@@ -743,7 +1078,7 @@ module ActiveMerchant #:nodoc:
743
1078
  parse_element(reply, node)
744
1079
  end
745
1080
  end
746
- elsif root = REXML::XPath.first(xml, "//soap:Fault")
1081
+ elsif root = REXML::XPath.first(xml, '//soap:Fault')
747
1082
  parse_element(reply, root)
748
1083
  reply[:message] = "#{reply[:faultcode]}: #{reply[:faultstring]}"
749
1084
  end
@@ -752,11 +1087,11 @@ module ActiveMerchant #:nodoc:
752
1087
 
753
1088
  def parse_element(reply, node)
754
1089
  if node.has_elements?
755
- node.elements.each{|e| parse_element(reply, e) }
1090
+ node.elements.each { |e| parse_element(reply, e) }
756
1091
  else
757
- if node.parent.name =~ /item/
1092
+ if /item/.match?(node.parent.name)
758
1093
  parent = node.parent.name
759
- parent += '_' + node.parent.attributes["id"] if node.parent.attributes["id"]
1094
+ parent += '_' + node.parent.attributes['id'] if node.parent.attributes['id']
760
1095
  parent += '_'
761
1096
  end
762
1097
  reply["#{parent}#{node.name}".to_sym] ||= node.text
@@ -766,12 +1101,35 @@ module ActiveMerchant #:nodoc:
766
1101
 
767
1102
  def reason_message(reason_code)
768
1103
  return if reason_code.blank?
1104
+
769
1105
  @@response_codes[:"r#{reason_code}"]
770
1106
  end
771
1107
 
772
1108
  def authorization_from(response, action, amount, options)
773
1109
  [options[:order_id], response[:requestID], response[:requestToken], action, amount,
774
- options[:currency], response[:subscriptionID]].join(";")
1110
+ options[:currency], response[:subscriptionID], options[:payment_method]].join(';')
1111
+ end
1112
+
1113
+ def in_fraud_review?(response)
1114
+ response[:decision] == @@decision_codes[:review]
1115
+ end
1116
+
1117
+ def success?(response)
1118
+ response[:decision] == @@decision_codes[:accept]
1119
+ end
1120
+
1121
+ def message_from(response)
1122
+ if response[:reasonCode] == '101' && response[:missingField]
1123
+ "#{response[:message]}: #{response[:missingField]}"
1124
+ elsif response[:reasonCode] == '102' && response[:invalidField]
1125
+ "#{response[:message]}: #{response[:invalidField]}"
1126
+ else
1127
+ response[:message]
1128
+ end
1129
+ end
1130
+
1131
+ def eligible_for_zero_auth?(payment_method, options = {})
1132
+ payment_method.is_a?(CreditCard) && options[:zero_amount_auth]
775
1133
  end
776
1134
  end
777
1135
  end