archetype2142_activemerchant 1.124.0

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