activemerchant 1.45.0 → 1.126.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (288) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG +2167 -2
  3. data/CONTRIBUTORS +57 -0
  4. data/README.md +62 -41
  5. data/lib/active_merchant/billing/avs_result.rb +25 -28
  6. data/lib/active_merchant/billing/base.rb +11 -35
  7. data/lib/active_merchant/billing/check.rb +28 -24
  8. data/lib/active_merchant/billing/compatibility.rb +10 -12
  9. data/lib/active_merchant/billing/credit_card.rb +141 -69
  10. data/lib/active_merchant/billing/credit_card_formatting.rb +4 -4
  11. data/lib/active_merchant/billing/credit_card_methods.rb +348 -52
  12. data/lib/active_merchant/billing/cvv_result.rb +0 -1
  13. data/lib/active_merchant/billing/gateway.rb +125 -61
  14. data/lib/active_merchant/billing/gateways/adyen.rb +633 -127
  15. data/lib/active_merchant/billing/gateways/airwallex.rb +341 -0
  16. data/lib/active_merchant/billing/gateways/allied_wallet.rb +205 -0
  17. data/lib/active_merchant/billing/gateways/authorize_net.rb +883 -195
  18. data/lib/active_merchant/billing/gateways/authorize_net_arb.rb +31 -24
  19. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +104 -103
  20. data/lib/active_merchant/billing/gateways/axcessms.rb +179 -0
  21. data/lib/active_merchant/billing/gateways/balanced.rb +72 -65
  22. data/lib/active_merchant/billing/gateways/bambora_apac.rb +222 -0
  23. data/lib/active_merchant/billing/gateways/bank_frick.rb +16 -16
  24. data/lib/active_merchant/billing/gateways/banwire.rb +24 -13
  25. data/lib/active_merchant/billing/gateways/barclaycard_smartpay.rb +397 -0
  26. data/lib/active_merchant/billing/gateways/barclays_epdq_extra_plus.rb +7 -7
  27. data/lib/active_merchant/billing/gateways/be2bill.rb +7 -7
  28. data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +143 -62
  29. data/lib/active_merchant/billing/gateways/beanstream.rb +45 -13
  30. data/lib/active_merchant/billing/gateways/beanstream_interac.rb +13 -10
  31. data/lib/active_merchant/billing/gateways/blue_pay.rb +549 -506
  32. data/lib/active_merchant/billing/gateways/blue_snap.rb +623 -0
  33. data/lib/active_merchant/billing/gateways/bogus.rb +82 -36
  34. data/lib/active_merchant/billing/gateways/borgun.rb +61 -40
  35. data/lib/active_merchant/billing/gateways/bpoint.rb +277 -0
  36. data/lib/active_merchant/billing/gateways/braintree/braintree_common.rb +21 -2
  37. data/lib/active_merchant/billing/gateways/braintree/token_nonce.rb +113 -0
  38. data/lib/active_merchant/billing/gateways/braintree.rb +3 -3
  39. data/lib/active_merchant/billing/gateways/braintree_blue.rb +592 -203
  40. data/lib/active_merchant/billing/gateways/braintree_orange.rb +3 -4
  41. data/lib/active_merchant/billing/gateways/bridge_pay.rb +116 -61
  42. data/lib/active_merchant/billing/gateways/cams.rb +230 -0
  43. data/lib/active_merchant/billing/gateways/card_connect.rb +320 -0
  44. data/lib/active_merchant/billing/gateways/card_save.rb +7 -9
  45. data/lib/active_merchant/billing/gateways/card_stream.rb +248 -97
  46. data/lib/active_merchant/billing/gateways/cardknox.rb +327 -0
  47. data/lib/active_merchant/billing/gateways/cardprocess.rb +256 -0
  48. data/lib/active_merchant/billing/gateways/cashnet.rb +70 -26
  49. data/lib/active_merchant/billing/gateways/cc5.rb +14 -17
  50. data/lib/active_merchant/billing/gateways/cecabank.rb +73 -53
  51. data/lib/active_merchant/billing/gateways/cenpos.rb +328 -0
  52. data/lib/active_merchant/billing/gateways/checkout.rb +32 -33
  53. data/lib/active_merchant/billing/gateways/checkout_v2.rb +340 -0
  54. data/lib/active_merchant/billing/gateways/citrus_pay.rb +21 -0
  55. data/lib/active_merchant/billing/gateways/clearhaus.rb +219 -0
  56. data/lib/active_merchant/billing/gateways/commercegate.rb +11 -12
  57. data/lib/active_merchant/billing/gateways/conekta.rb +55 -34
  58. data/lib/active_merchant/billing/gateways/creditcall.rb +272 -0
  59. data/lib/active_merchant/billing/gateways/credorax.rb +506 -0
  60. data/lib/active_merchant/billing/gateways/ct_payment.rb +269 -0
  61. data/lib/active_merchant/billing/gateways/culqi.rb +279 -0
  62. data/lib/active_merchant/billing/gateways/cyber_source.rb +637 -221
  63. data/lib/active_merchant/billing/gateways/d_local.rb +303 -0
  64. data/lib/active_merchant/billing/gateways/data_cash.rb +57 -355
  65. data/lib/active_merchant/billing/gateways/decidir.rb +347 -0
  66. data/lib/active_merchant/billing/gateways/decidir_plus.rb +344 -0
  67. data/lib/active_merchant/billing/gateways/dibs.rb +199 -0
  68. data/lib/active_merchant/billing/gateways/digitzs.rb +295 -0
  69. data/lib/active_merchant/billing/gateways/ebanx.rb +334 -0
  70. data/lib/active_merchant/billing/gateways/efsnet.rb +46 -50
  71. data/lib/active_merchant/billing/gateways/elavon.rb +377 -250
  72. data/lib/active_merchant/billing/gateways/element.rb +386 -0
  73. data/lib/active_merchant/billing/gateways/epay.rb +92 -71
  74. data/lib/active_merchant/billing/gateways/evo_ca.rb +13 -14
  75. data/lib/active_merchant/billing/gateways/eway.rb +85 -73
  76. data/lib/active_merchant/billing/gateways/eway_managed.rb +85 -87
  77. data/lib/active_merchant/billing/gateways/eway_rapid.rb +134 -80
  78. data/lib/active_merchant/billing/gateways/exact.rb +37 -36
  79. data/lib/active_merchant/billing/gateways/ezic.rb +195 -0
  80. data/lib/active_merchant/billing/gateways/fat_zebra.rb +124 -74
  81. data/lib/active_merchant/billing/gateways/federated_canada.rb +11 -13
  82. data/lib/active_merchant/billing/gateways/finansbank.rb +4 -5
  83. data/lib/active_merchant/billing/gateways/first_giving.rb +23 -23
  84. data/lib/active_merchant/billing/gateways/first_pay.rb +45 -23
  85. data/lib/active_merchant/billing/gateways/firstdata_e4.rb +184 -87
  86. data/lib/active_merchant/billing/gateways/firstdata_e4_v27.rb +505 -0
  87. data/lib/active_merchant/billing/gateways/flo2cash.rb +215 -0
  88. data/lib/active_merchant/billing/gateways/flo2cash_simple.rb +20 -0
  89. data/lib/active_merchant/billing/gateways/forte.rb +286 -0
  90. data/lib/active_merchant/billing/gateways/garanti.rb +31 -32
  91. data/lib/active_merchant/billing/gateways/global_collect.rb +507 -0
  92. data/lib/active_merchant/billing/gateways/global_transport.rb +25 -15
  93. data/lib/active_merchant/billing/gateways/hdfc.rb +55 -57
  94. data/lib/active_merchant/billing/gateways/hps.rb +252 -68
  95. data/lib/active_merchant/billing/gateways/iats_payments.rb +99 -38
  96. data/lib/active_merchant/billing/gateways/in_context_paypal_express.rb +15 -0
  97. data/lib/active_merchant/billing/gateways/inspire.rb +48 -48
  98. data/lib/active_merchant/billing/gateways/instapay.rb +10 -14
  99. data/lib/active_merchant/billing/gateways/ipg.rb +415 -0
  100. data/lib/active_merchant/billing/gateways/ipp.rb +176 -0
  101. data/lib/active_merchant/billing/gateways/iridium.rb +254 -244
  102. data/lib/active_merchant/billing/gateways/itransact.rb +14 -14
  103. data/lib/active_merchant/billing/gateways/iveri.rb +254 -0
  104. data/lib/active_merchant/billing/gateways/ixopay.rb +320 -0
  105. data/lib/active_merchant/billing/gateways/jetpay.rb +200 -80
  106. data/lib/active_merchant/billing/gateways/jetpay_v2.rb +432 -0
  107. data/lib/active_merchant/billing/gateways/komoju.rb +115 -0
  108. data/lib/active_merchant/billing/gateways/kushki.rb +277 -0
  109. data/lib/active_merchant/billing/gateways/latitude19.rb +412 -0
  110. data/lib/active_merchant/billing/gateways/linkpoint.rb +95 -85
  111. data/lib/active_merchant/billing/gateways/litle.rb +371 -94
  112. data/lib/active_merchant/billing/gateways/mastercard.rb +293 -0
  113. data/lib/active_merchant/billing/gateways/maxipago.rb +146 -123
  114. data/lib/active_merchant/billing/gateways/mercado_pago.rb +331 -0
  115. data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +47 -23
  116. data/lib/active_merchant/billing/gateways/merchant_one.rb +16 -20
  117. data/lib/active_merchant/billing/gateways/merchant_partners.rb +245 -0
  118. data/lib/active_merchant/billing/gateways/merchant_ware.rb +54 -60
  119. data/lib/active_merchant/billing/gateways/merchant_ware_version_four.rb +60 -44
  120. data/lib/active_merchant/billing/gateways/merchant_warrior.rb +76 -23
  121. data/lib/active_merchant/billing/gateways/mercury.rb +73 -54
  122. data/lib/active_merchant/billing/gateways/metrics_global.rb +33 -43
  123. data/lib/active_merchant/billing/gateways/micropayment.rb +182 -0
  124. data/lib/active_merchant/billing/gateways/migs/migs_codes.rb +7 -7
  125. data/lib/active_merchant/billing/gateways/migs.rb +101 -37
  126. data/lib/active_merchant/billing/gateways/mit.rb +260 -0
  127. data/lib/active_merchant/billing/gateways/modern_payments.rb +3 -3
  128. data/lib/active_merchant/billing/gateways/modern_payments_cim.rb +30 -34
  129. data/lib/active_merchant/billing/gateways/moka.rb +290 -0
  130. data/lib/active_merchant/billing/gateways/monei.rb +422 -0
  131. data/lib/active_merchant/billing/gateways/moneris.rb +236 -72
  132. data/lib/active_merchant/billing/gateways/money_movers.rb +11 -13
  133. data/lib/active_merchant/billing/gateways/mundipagg.rb +363 -0
  134. data/lib/active_merchant/billing/gateways/nab_transact.rb +87 -68
  135. data/lib/active_merchant/billing/gateways/ncr_secure_pay.rb +163 -0
  136. data/lib/active_merchant/billing/gateways/net_registry.rb +12 -12
  137. data/lib/active_merchant/billing/gateways/netaxept.rb +33 -34
  138. data/lib/active_merchant/billing/gateways/netbanx.rb +376 -0
  139. data/lib/active_merchant/billing/gateways/netbilling.rb +82 -43
  140. data/lib/active_merchant/billing/gateways/netpay.rb +10 -10
  141. data/lib/active_merchant/billing/gateways/network_merchants.rb +7 -11
  142. data/lib/active_merchant/billing/gateways/nmi.rb +279 -174
  143. data/lib/active_merchant/billing/gateways/ogone.rb +96 -50
  144. data/lib/active_merchant/billing/gateways/omise.rb +323 -0
  145. data/lib/active_merchant/billing/gateways/openpay.rb +58 -23
  146. data/lib/active_merchant/billing/gateways/opp.rb +394 -0
  147. data/lib/active_merchant/billing/gateways/optimal_payment.rb +87 -69
  148. data/lib/active_merchant/billing/gateways/orbital/orbital_soft_descriptors.rb +5 -7
  149. data/lib/active_merchant/billing/gateways/orbital.rb +771 -328
  150. data/lib/active_merchant/billing/gateways/pac_net_raven.rb +31 -32
  151. data/lib/active_merchant/billing/gateways/pagarme.rb +239 -0
  152. data/lib/active_merchant/billing/gateways/pago_facil.rb +12 -14
  153. data/lib/active_merchant/billing/gateways/pay_arc.rb +392 -0
  154. data/lib/active_merchant/billing/gateways/pay_conex.rb +245 -0
  155. data/lib/active_merchant/billing/gateways/pay_gate_xml.rb +84 -68
  156. data/lib/active_merchant/billing/gateways/pay_hub.rb +213 -0
  157. data/lib/active_merchant/billing/gateways/pay_junction.rb +37 -37
  158. data/lib/active_merchant/billing/gateways/pay_junction_v2.rb +206 -0
  159. data/lib/active_merchant/billing/gateways/pay_secure.rb +15 -17
  160. data/lib/active_merchant/billing/gateways/pay_trace.rb +404 -0
  161. data/lib/active_merchant/billing/gateways/paybox_direct.rb +85 -49
  162. data/lib/active_merchant/billing/gateways/payeezy.rb +458 -0
  163. data/lib/active_merchant/billing/gateways/payex.rb +39 -42
  164. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +67 -41
  165. data/lib/active_merchant/billing/gateways/payflow/payflow_express_response.rb +11 -8
  166. data/lib/active_merchant/billing/gateways/payflow/payflow_response.rb +3 -3
  167. data/lib/active_merchant/billing/gateways/payflow.rb +215 -46
  168. data/lib/active_merchant/billing/gateways/payflow_express.rb +64 -68
  169. data/lib/active_merchant/billing/gateways/payflow_express_uk.rb +2 -3
  170. data/lib/active_merchant/billing/gateways/payflow_uk.rb +5 -6
  171. data/lib/active_merchant/billing/gateways/payment_express.rb +78 -58
  172. data/lib/active_merchant/billing/gateways/paymentez.rb +353 -0
  173. data/lib/active_merchant/billing/gateways/paymill.rb +163 -75
  174. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +55 -7
  175. data/lib/active_merchant/billing/gateways/paypal/paypal_recurring_api.rb +1 -1
  176. data/lib/active_merchant/billing/gateways/paypal.rb +37 -18
  177. data/lib/active_merchant/billing/gateways/paypal_ca.rb +2 -2
  178. data/lib/active_merchant/billing/gateways/paypal_digital_goods.rb +5 -5
  179. data/lib/active_merchant/billing/gateways/paypal_express.rb +12 -6
  180. data/lib/active_merchant/billing/gateways/paypal_express_common.rb +3 -3
  181. data/lib/active_merchant/billing/gateways/paysafe.rb +412 -0
  182. data/lib/active_merchant/billing/gateways/payscout.rb +10 -13
  183. data/lib/active_merchant/billing/gateways/paystation.rb +96 -91
  184. data/lib/active_merchant/billing/gateways/payu_in.rb +249 -0
  185. data/lib/active_merchant/billing/gateways/payu_latam.rb +479 -0
  186. data/lib/active_merchant/billing/gateways/payway.rb +27 -27
  187. data/lib/active_merchant/billing/gateways/payway_dot_com.rb +253 -0
  188. data/lib/active_merchant/billing/gateways/pin.rb +113 -37
  189. data/lib/active_merchant/billing/gateways/plugnpay.rb +82 -82
  190. data/lib/active_merchant/billing/gateways/priority.rb +369 -0
  191. data/lib/active_merchant/billing/gateways/pro_pay.rb +325 -0
  192. data/lib/active_merchant/billing/gateways/psigate.rb +55 -44
  193. data/lib/active_merchant/billing/gateways/psl_card.rb +32 -40
  194. data/lib/active_merchant/billing/gateways/qbms.rb +86 -76
  195. data/lib/active_merchant/billing/gateways/quantum.rb +21 -23
  196. data/lib/active_merchant/billing/gateways/quickbooks.rb +377 -0
  197. data/lib/active_merchant/billing/gateways/quickpay/quickpay_common.rb +184 -0
  198. data/lib/active_merchant/billing/gateways/quickpay/quickpay_v10.rb +297 -0
  199. data/lib/active_merchant/billing/gateways/quickpay/quickpay_v4to7.rb +226 -0
  200. data/lib/active_merchant/billing/gateways/quickpay.rb +10 -353
  201. data/lib/active_merchant/billing/gateways/qvalent.rb +305 -0
  202. data/lib/active_merchant/billing/gateways/rapyd.rb +258 -0
  203. data/lib/active_merchant/billing/gateways/realex.rb +154 -52
  204. data/lib/active_merchant/billing/gateways/redsys.rb +488 -161
  205. data/lib/active_merchant/billing/gateways/s5.rb +247 -0
  206. data/lib/active_merchant/billing/gateways/safe_charge.rb +298 -0
  207. data/lib/active_merchant/billing/gateways/sage.rb +404 -133
  208. data/lib/active_merchant/billing/gateways/sage_pay.rb +145 -109
  209. data/lib/active_merchant/billing/gateways/sallie_mae.rb +13 -15
  210. data/lib/active_merchant/billing/gateways/secure_net.rb +62 -54
  211. data/lib/active_merchant/billing/gateways/secure_pay.rb +32 -42
  212. data/lib/active_merchant/billing/gateways/secure_pay_au.rb +36 -27
  213. data/lib/active_merchant/billing/gateways/secure_pay_tech.rb +14 -16
  214. data/lib/active_merchant/billing/gateways/securion_pay.rb +265 -0
  215. data/lib/active_merchant/billing/gateways/simetrik.rb +362 -0
  216. data/lib/active_merchant/billing/gateways/skip_jack.rb +52 -54
  217. data/lib/active_merchant/billing/gateways/smart_ps.rb +51 -60
  218. data/lib/active_merchant/billing/gateways/so_easy_pay.rb +29 -29
  219. data/lib/active_merchant/billing/gateways/spreedly_core.rb +108 -43
  220. data/lib/active_merchant/billing/gateways/stripe.rb +536 -120
  221. data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +516 -0
  222. data/lib/active_merchant/billing/gateways/swipe_checkout.rb +19 -25
  223. data/lib/active_merchant/billing/gateways/telr.rb +273 -0
  224. data/lib/active_merchant/billing/gateways/tns.rb +16 -217
  225. data/lib/active_merchant/billing/gateways/trans_first.rb +148 -34
  226. data/lib/active_merchant/billing/gateways/trans_first_transaction_express.rb +612 -0
  227. data/lib/active_merchant/billing/gateways/transact_pro.rb +222 -0
  228. data/lib/active_merchant/billing/gateways/transax.rb +6 -8
  229. data/lib/active_merchant/billing/gateways/transnational.rb +1 -2
  230. data/lib/active_merchant/billing/gateways/trexle.rb +221 -0
  231. data/lib/active_merchant/billing/gateways/trust_commerce.rb +162 -89
  232. data/lib/active_merchant/billing/gateways/usa_epay.rb +5 -6
  233. data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +332 -236
  234. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +185 -72
  235. data/lib/active_merchant/billing/gateways/vanco.rb +294 -0
  236. data/lib/active_merchant/billing/gateways/verifi.rb +52 -53
  237. data/lib/active_merchant/billing/gateways/viaklix.rb +19 -31
  238. data/lib/active_merchant/billing/gateways/visanet_peru.rb +250 -0
  239. data/lib/active_merchant/billing/gateways/vpos.rb +220 -0
  240. data/lib/active_merchant/billing/gateways/webpay.rb +9 -9
  241. data/lib/active_merchant/billing/gateways/wepay.rb +108 -62
  242. data/lib/active_merchant/billing/gateways/wirecard.rb +52 -43
  243. data/lib/active_merchant/billing/gateways/wompi.rb +193 -0
  244. data/lib/active_merchant/billing/gateways/world_net.rb +345 -0
  245. data/lib/active_merchant/billing/gateways/worldpay.rb +725 -121
  246. data/lib/active_merchant/billing/gateways/worldpay_online_payments.rb +208 -0
  247. data/lib/active_merchant/billing/gateways/worldpay_us.rb +79 -39
  248. data/lib/active_merchant/billing/gateways.rb +8 -11
  249. data/lib/active_merchant/billing/model.rb +2 -2
  250. data/lib/active_merchant/billing/network_tokenization_credit_card.rb +39 -0
  251. data/lib/active_merchant/billing/payment_token.rb +1 -1
  252. data/lib/active_merchant/billing/rails.rb +1 -1
  253. data/lib/active_merchant/billing/response.rb +19 -13
  254. data/lib/active_merchant/billing/three_d_secure_eci_mapper.rb +27 -0
  255. data/lib/active_merchant/billing.rb +3 -0
  256. data/lib/active_merchant/connection.rb +196 -0
  257. data/lib/active_merchant/country.rb +13 -8
  258. data/lib/active_merchant/errors.rb +6 -0
  259. data/lib/active_merchant/net_http_ssl_connection.rb +11 -0
  260. data/lib/active_merchant/network_connection_retries.rb +78 -0
  261. data/lib/active_merchant/post_data.rb +26 -0
  262. data/lib/active_merchant/posts_data.rb +92 -0
  263. data/lib/active_merchant/version.rb +1 -1
  264. data/lib/active_merchant.rb +14 -59
  265. data/lib/activemerchant.rb +1 -1
  266. data/lib/certs/cacert.pem +3214 -0
  267. data/lib/support/gateway_support.rb +8 -10
  268. data/lib/support/outbound_hosts.rb +13 -10
  269. data/lib/support/ssl_verify.rb +9 -14
  270. data/lib/support/ssl_version.rb +86 -0
  271. metadata +136 -94
  272. checksums.yaml.gz.sig +0 -1
  273. data/lib/active_merchant/billing/gateways/app55.rb +0 -176
  274. data/lib/active_merchant/billing/gateways/barclays_epdq.rb +0 -314
  275. data/lib/active_merchant/billing/gateways/certo_direct.rb +0 -278
  276. data/lib/active_merchant/billing/gateways/ideal/ideal_base.rb +0 -246
  277. data/lib/active_merchant/billing/gateways/ideal/ideal_rabobank.pem +0 -13
  278. data/lib/active_merchant/billing/gateways/ideal/ideal_response.rb +0 -29
  279. data/lib/active_merchant/billing/gateways/ideal_rabobank.rb +0 -66
  280. data/lib/active_merchant/billing/gateways/moneris_us.rb +0 -291
  281. data/lib/active_merchant/billing/gateways/sage/sage_bankcard.rb +0 -87
  282. data/lib/active_merchant/billing/gateways/sage/sage_core.rb +0 -114
  283. data/lib/active_merchant/billing/gateways/sage/sage_vault.rb +0 -149
  284. data/lib/active_merchant/billing/gateways/sage/sage_virtual_check.rb +0 -102
  285. data/lib/active_merchant/billing/gateways/vindicia.rb +0 -385
  286. data/lib/active_merchant/offsite_payments_shim.rb +0 -19
  287. data.tar.gz.sig +0 -0
  288. metadata.gz.sig +0 -0
@@ -1,5 +1,5 @@
1
- require File.dirname(__FILE__) + '/orbital/orbital_soft_descriptors'
2
- require "rexml/document"
1
+ require 'active_merchant/billing/gateways/orbital/orbital_soft_descriptors'
2
+ require 'rexml/document'
3
3
 
4
4
  module ActiveMerchant #:nodoc:
5
5
  module Billing #:nodoc:
@@ -28,18 +28,21 @@ module ActiveMerchant #:nodoc:
28
28
  # Company will automatically be affiliated.
29
29
 
30
30
  class OrbitalGateway < Gateway
31
- API_VERSION = "5.6"
31
+ include Empty
32
+
33
+ API_VERSION = '8.1'
32
34
 
33
35
  POST_HEADERS = {
34
- "MIME-Version" => "1.1",
35
- "Content-Type" => "application/PTI56",
36
- "Content-transfer-encoding" => "text",
37
- "Request-number" => '1',
38
- "Document-type" => "Request",
39
- "Interface-Version" => "Ruby|ActiveMerchant|Proprietary Gateway"
36
+ 'MIME-Version' => '1.1',
37
+ 'Content-Type' => "application/PTI#{API_VERSION.delete('.')}",
38
+ 'Content-transfer-encoding' => 'text',
39
+ 'Request-number' => '1',
40
+ 'Document-type' => 'Request',
41
+ 'Interface-Version' => 'Ruby|ActiveMerchant|Proprietary Gateway'
40
42
  }
41
43
 
42
44
  SUCCESS = '0'
45
+ APPROVAL_SUCCESS = '1'
43
46
 
44
47
  APPROVED = [
45
48
  '00', # Approved
@@ -58,64 +61,69 @@ module ActiveMerchant #:nodoc:
58
61
  '93', # Approved high fraud
59
62
  '94', # Approved fraud service unavailable
60
63
  'E7', # Stored
61
- 'PA' # Partial approval
64
+ 'PA', # Partial approval
65
+ 'P1' # ECP - AVS - Account Status Verification and/or AOA data is in a positive status.
62
66
  ]
63
67
 
64
68
  class_attribute :secondary_test_url, :secondary_live_url
65
69
 
66
- self.test_url = "https://orbitalvar1.paymentech.net/authorize"
67
- self.secondary_test_url = "https://orbitalvar2.paymentech.net/authorize"
70
+ self.test_url = 'https://orbitalvar1.chasepaymentech.com/authorize'
71
+ self.secondary_test_url = 'https://orbitalvar2.chasepaymentech.com/authorize'
68
72
 
69
- self.live_url = "https://orbital1.paymentech.net/authorize"
70
- self.secondary_live_url = "https://orbital2.paymentech.net/authorize"
73
+ self.live_url = 'https://orbital1.chasepaymentech.com/authorize'
74
+ self.secondary_live_url = 'https://orbital2.chasepaymentech.com/authorize'
71
75
 
72
- self.supported_countries = ["US", "CA"]
73
- self.default_currency = "CAD"
74
- self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb]
76
+ self.supported_countries = %w[US CA]
77
+ self.default_currency = 'CAD'
78
+ self.supported_cardtypes = %i[visa master american_express discover diners_club jcb]
75
79
 
76
80
  self.display_name = 'Orbital Paymentech'
77
81
  self.homepage_url = 'http://chasepaymentech.com/'
78
82
 
79
83
  self.money_format = :cents
80
84
 
81
- AVS_SUPPORTED_COUNTRIES = ['US', 'CA', 'UK', 'GB']
85
+ AVS_SUPPORTED_COUNTRIES = %w[US CA UK GB]
82
86
 
83
87
  CURRENCY_CODES = {
84
- "AUD" => '036',
85
- "CAD" => '124',
86
- "CZK" => '203',
87
- "DKK" => '208',
88
- "HKD" => '344',
89
- "ICK" => '352',
90
- "JPY" => '392',
91
- "MXN" => '484',
92
- "NZD" => '554',
93
- "NOK" => '578',
94
- "SGD" => '702',
95
- "SEK" => '752',
96
- "CHF" => '756',
97
- "GBP" => '826',
98
- "USD" => '840',
99
- "EUR" => '978'
88
+ 'AUD' => '036',
89
+ 'BRL' => '986',
90
+ 'CAD' => '124',
91
+ 'CLP' => '152',
92
+ 'CZK' => '203',
93
+ 'DKK' => '208',
94
+ 'HKD' => '344',
95
+ 'ICK' => '352',
96
+ 'JPY' => '392',
97
+ 'MXN' => '484',
98
+ 'NZD' => '554',
99
+ 'NOK' => '578',
100
+ 'SGD' => '702',
101
+ 'SEK' => '752',
102
+ 'CHF' => '756',
103
+ 'GBP' => '826',
104
+ 'USD' => '840',
105
+ 'EUR' => '978'
100
106
  }
101
107
 
102
108
  CURRENCY_EXPONENTS = {
103
- "AUD" => '2',
104
- "CAD" => '2',
105
- "CZK" => '2',
106
- "DKK" => '2',
107
- "HKD" => '2',
108
- "ICK" => '2',
109
- "JPY" => '0',
110
- "MXN" => '2',
111
- "NZD" => '2',
112
- "NOK" => '2',
113
- "SGD" => '2',
114
- "SEK" => '2',
115
- "CHF" => '2',
116
- "GBP" => '2',
117
- "USD" => '2',
118
- "EUR" => '2'
109
+ 'AUD' => '2',
110
+ 'BRL' => '2',
111
+ 'CAD' => '2',
112
+ 'CLP' => '2',
113
+ 'CZK' => '2',
114
+ 'DKK' => '2',
115
+ 'HKD' => '2',
116
+ 'ICK' => '2',
117
+ 'JPY' => '0',
118
+ 'MXN' => '2',
119
+ 'NZD' => '2',
120
+ 'NOK' => '2',
121
+ 'SGD' => '2',
122
+ 'SEK' => '2',
123
+ 'CHF' => '2',
124
+ 'GBP' => '2',
125
+ 'USD' => '2',
126
+ 'EUR' => '2'
119
127
  }
120
128
 
121
129
  # INDUSTRY TYPES
@@ -175,72 +183,99 @@ module ActiveMerchant #:nodoc:
175
183
  USE_ORDER_ID = 'O' # Use OrderID field
176
184
  USE_COMMENTS = 'D' # Use Comments field
177
185
 
178
- SENSITIVE_FIELDS = [:account_num]
186
+ SENSITIVE_FIELDS = %i[account_num cc_account_num]
187
+
188
+ # Bank account types to be used for check processing
189
+ ACCOUNT_TYPE = {
190
+ 'savings' => 'S',
191
+ 'checking' => 'C'
192
+ }
179
193
 
180
194
  def initialize(options = {})
181
195
  requires!(options, :merchant_id)
182
196
  requires!(options, :login, :password) unless options[:ip_authentication]
183
197
  super
198
+ @options[:merchant_id] = @options[:merchant_id].to_s
184
199
  end
185
200
 
186
201
  # A – Authorization request
187
- def authorize(money, creditcard, options = {})
188
- order = build_new_order_xml(AUTH_ONLY, money, options) do |xml|
189
- add_creditcard(xml, creditcard, options[:currency])
190
- add_address(xml, creditcard, options)
191
- if @options[:customer_profiles]
192
- add_customer_data(xml, creditcard, options)
193
- add_managed_billing(xml, options)
194
- end
202
+ def authorize(money, payment_source, options = {})
203
+ # ECP for Orbital requires $0 prenotes so ensure
204
+ # if we are doing a force capture with a check, that
205
+ # we do a purchase here
206
+ return purchase(money, payment_source, options) if force_capture_with_echeck?(payment_source, options)
207
+
208
+ order = build_new_auth_purchase_order(AUTH_ONLY, money, payment_source, options)
209
+
210
+ commit(order, :authorize, options[:retry_logic], options[:trace_number])
211
+ end
212
+
213
+ def verify(credit_card, options = {})
214
+ amount = options[:verify_amount] ? options[:verify_amount].to_i : default_verify_amount(credit_card)
215
+ MultiResponse.run(:use_first_response) do |r|
216
+ r.process { authorize(amount, credit_card, options) }
217
+ r.process(:ignore_result) { void(r.authorization) } unless amount == 0
195
218
  end
196
- commit(order, :authorize, options[:trace_number])
197
219
  end
198
220
 
199
221
  # AC – Authorization and Capture
200
- def purchase(money, creditcard, options = {})
201
- order = build_new_order_xml(AUTH_AND_CAPTURE, money, options) do |xml|
202
- add_creditcard(xml, creditcard, options[:currency])
203
- add_address(xml, creditcard, options)
204
- if @options[:customer_profiles]
205
- add_customer_data(xml, creditcard, options)
206
- add_managed_billing(xml, options)
207
- end
208
- end
209
- commit(order, :purchase, options[:trace_number])
222
+ def purchase(money, payment_source, options = {})
223
+ action = options[:force_capture] ? FORCE_AUTH_AND_CAPTURE : AUTH_AND_CAPTURE
224
+ order = build_new_auth_purchase_order(action, money, payment_source, options)
225
+
226
+ commit(order, :purchase, options[:retry_logic], options[:trace_number])
210
227
  end
211
228
 
212
229
  # MFC - Mark For Capture
213
230
  def capture(money, authorization, options = {})
214
- commit(build_mark_for_capture_xml(money, authorization, options), :capture)
231
+ commit(build_mark_for_capture_xml(money, authorization, options), :capture, options[:retry_logic], options[:trace_number])
215
232
  end
216
233
 
217
234
  # R – Refund request
218
235
  def refund(money, authorization, options = {})
219
- order = build_new_order_xml(REFUND, money, options.merge(:authorization => authorization)) do |xml|
220
- add_refund(xml, options[:currency])
236
+ payment_method = options[:payment_method]
237
+ order = build_new_order_xml(REFUND, money, payment_method, options.merge(authorization: authorization)) do |xml|
238
+ if payment_method.is_a?(Check)
239
+ add_echeck(xml, payment_method, options)
240
+ else
241
+ add_refund_payment_source(xml, options[:currency])
242
+ end
221
243
  xml.tag! :CustomerRefNum, options[:customer_ref_num] if @options[:customer_profiles] && options[:profile_txn]
222
244
  end
223
- commit(order, :refund, options[:trace_number])
245
+
246
+ commit(order, :refund, options[:retry_logic], options[:trace_number])
224
247
  end
225
248
 
226
- def credit(money, authorization, options= {})
227
- ActiveMerchant.deprecated CREDIT_DEPRECATION_MESSAGE
228
- refund(money, authorization, options)
249
+ def credit(money, payment_method, options = {})
250
+ order = build_new_order_xml(REFUND, money, payment_method, options) do |xml|
251
+ add_payment_source(xml, payment_method, options)
252
+ end
253
+
254
+ commit(order, :refund, options[:retry_logic], options[:trace_number])
229
255
  end
230
256
 
231
257
  def void(authorization, options = {}, deprecated = {})
232
- if(!options.kind_of?(Hash))
233
- ActiveMerchant.deprecated("Calling the void method with an amount parameter is deprecated and will be removed in a future version.")
234
- return void(options, deprecated.merge(:amount => authorization))
258
+ if !options.kind_of?(Hash)
259
+ ActiveMerchant.deprecated('Calling the void method with an amount parameter is deprecated and will be removed in a future version.')
260
+ return void(options, deprecated.merge(amount: authorization))
235
261
  end
236
262
 
237
263
  order = build_void_request_xml(authorization, options)
238
- commit(order, :void, options[:trace_number])
264
+
265
+ commit(order, :void, options[:retry_logic], options[:trace_number])
239
266
  end
240
267
 
268
+ def default_verify_amount(credit_card)
269
+ allow_zero_auth?(credit_card) ? 0 : 100
270
+ end
271
+
272
+ def allow_zero_auth?(credit_card)
273
+ # Discover does not support a $0.00 authorization instead use $1.00
274
+ %w(visa master american_express diners_club jcb).include?(credit_card.brand)
275
+ end
241
276
 
242
277
  # ==== Customer Profiles
243
- # :customer_ref_num should be set unless your happy with Orbital providing one
278
+ # :customer_ref_num should be set unless you're happy with Orbital providing one
244
279
  #
245
280
  # :customer_profile_order_override_ind can be set to map
246
281
  # the CustomerRefNum to OrderID or Comments. Defaults to 'NO' - no mapping
@@ -260,57 +295,110 @@ module ActiveMerchant #:nodoc:
260
295
  # 'I' - Inactive
261
296
  # 'MS' - Manual Suspend
262
297
 
263
- def add_customer_profile(creditcard, options = {})
264
- options.merge!(:customer_profile_action => CREATE)
265
- order = build_customer_request_xml(creditcard, options)
298
+ def add_customer_profile(credit_card, options = {})
299
+ options[:customer_profile_action] = CREATE
300
+ order = build_customer_request_xml(credit_card, options)
266
301
  commit(order, :add_customer_profile)
267
302
  end
268
303
 
269
- def update_customer_profile(creditcard, options = {})
270
- options.merge!(:customer_profile_action => UPDATE)
271
- order = build_customer_request_xml(creditcard, options)
304
+ def update_customer_profile(credit_card, options = {})
305
+ options[:customer_profile_action] = UPDATE
306
+ order = build_customer_request_xml(credit_card, options)
272
307
  commit(order, :update_customer_profile)
273
308
  end
274
309
 
275
310
  def retrieve_customer_profile(customer_ref_num)
276
- options = {:customer_profile_action => RETRIEVE, :customer_ref_num => customer_ref_num}
311
+ options = { customer_profile_action: RETRIEVE, customer_ref_num: customer_ref_num }
277
312
  order = build_customer_request_xml(nil, options)
278
313
  commit(order, :retrieve_customer_profile)
279
314
  end
280
315
 
281
316
  def delete_customer_profile(customer_ref_num)
282
- options = {:customer_profile_action => DELETE, :customer_ref_num => customer_ref_num}
317
+ options = { customer_profile_action: DELETE, customer_ref_num: customer_ref_num }
283
318
  order = build_customer_request_xml(nil, options)
284
319
  commit(order, :delete_customer_profile)
285
320
  end
286
321
 
322
+ def supports_network_tokenization?
323
+ true
324
+ end
325
+
326
+ def supports_scrubbing?
327
+ true
328
+ end
329
+
330
+ def scrub(transcript)
331
+ transcript.
332
+ gsub(%r((<OrbitalConnectionUsername>).+(</OrbitalConnectionUsername>)), '\1[FILTERED]\2').
333
+ gsub(%r((<OrbitalConnectionPassword>).+(</OrbitalConnectionPassword>)), '\1[FILTERED]\2').
334
+ gsub(%r((<AccountNum>).+(</AccountNum>)), '\1[FILTERED]\2').
335
+ # the response sometimes contains a new line that cuts off the end of the closing tag
336
+ gsub(%r((<CCAccountNum>).+(</CC)), '\1[FILTERED]\2').
337
+ gsub(%r((<CardSecVal>).+(</CardSecVal>)), '\1[FILTERED]\2').
338
+ gsub(%r((<MerchantID>).+(</MerchantID>)), '\1[FILTERED]\2').
339
+ gsub(%r((<CustomerMerchantID>).+(</CustomerMerchantID>)), '\1[FILTERED]\2').
340
+ gsub(%r((<CustomerProfileMessage>).+(</CustomerProfileMessage>)), '\1[FILTERED]\2').
341
+ gsub(%r((<CheckDDA>).+(</CheckDDA>)), '\1[FILTERED]\2').
342
+ gsub(%r((<BCRtNum>).+(</BCRtNum>)), '\1[FILTERED]\2').
343
+ gsub(%r((<DigitalTokenCryptogram>).+(</DigitalTokenCryptogram>)), '\1[FILTERED]\2')
344
+ end
345
+
287
346
  private
288
347
 
348
+ def force_capture_with_echeck?(payment_source, options)
349
+ return false unless options[:force_capture]
350
+ return false unless payment_source.is_a?(Check)
351
+
352
+ %w(W8 W9 ND).include?(options[:action_code])
353
+ end
354
+
355
+ #=====REFERENCE FIELDS=====
356
+
357
+ def add_customer_data(xml, credit_card, options)
358
+ add_customer_ref_num(xml, options)
359
+
360
+ return if options[:profile_txn]
361
+
362
+ xml.tag! :CustomerProfileFromOrderInd, profile_number(options) if add_profile_number?(options, credit_card)
363
+ xml.tag! :CustomerProfileOrderOverrideInd, options[:customer_profile_order_override_ind] || NO_MAPPING_TO_ORDER_DATA
364
+ end
365
+
366
+ def add_profile_number?(options, credit_card)
367
+ return true unless options[:customer_ref_num] && credit_card.nil?
368
+ end
369
+
370
+ def profile_number(options)
371
+ options[:customer_ref_num] ? USE_CUSTOMER_REF_NUM : AUTO_GENERATE
372
+ end
373
+
374
+ def add_customer_ref_num(xml, options)
375
+ xml.tag! :CustomerRefNum, options[:customer_ref_num] if options[:customer_ref_num]
376
+ end
377
+
378
+ def add_tx_ref_num(xml, authorization)
379
+ return unless authorization
380
+
381
+ xml.tag! :TxRefNum, split_authorization(authorization).first
382
+ end
383
+
289
384
  def authorization_string(*args)
290
- args.compact.join(";")
385
+ args.compact.join(';')
291
386
  end
292
387
 
293
388
  def split_authorization(authorization)
294
389
  authorization.split(';')
295
390
  end
296
391
 
297
- def add_customer_data(xml, creditcard, options)
298
- if options[:profile_txn]
299
- xml.tag! :CustomerRefNum, options[:customer_ref_num]
300
- else
301
- if options[:customer_ref_num]
302
- if creditcard
303
- xml.tag! :CustomerProfileFromOrderInd, USE_CUSTOMER_REF_NUM
304
- end
305
- xml.tag! :CustomerRefNum, options[:customer_ref_num]
306
- else
307
- xml.tag! :CustomerProfileFromOrderInd, AUTO_GENERATE
308
- end
309
- xml.tag! :CustomerProfileOrderOverrideInd, options[:customer_profile_order_override_ind] || NO_MAPPING_TO_ORDER_DATA
310
- end
392
+ #=====DESCRIPTOR FIELDS=====
393
+
394
+ def add_soft_descriptors(xml, descriptors)
395
+ return unless descriptors
396
+
397
+ add_soft_descriptors_from_specialized_class(xml, descriptors) if descriptors.is_a?(OrbitalSoftDescriptors)
398
+ add_soft_descriptors_from_hash(xml, descriptors) if descriptors.is_a?(Hash)
311
399
  end
312
400
 
313
- def add_soft_descriptors(xml, soft_desc)
401
+ def add_soft_descriptors_from_specialized_class(xml, soft_desc)
314
402
  xml.tag! :SDMerchantName, soft_desc.merchant_name if soft_desc.merchant_name
315
403
  xml.tag! :SDProductDescription, soft_desc.product_description if soft_desc.product_description
316
404
  xml.tag! :SDMerchantCity, soft_desc.merchant_city if soft_desc.merchant_city
@@ -319,63 +407,184 @@ module ActiveMerchant #:nodoc:
319
407
  xml.tag! :SDMerchantEmail, soft_desc.merchant_email if soft_desc.merchant_email
320
408
  end
321
409
 
322
- def add_address(xml, creditcard, options)
323
- if(address = (options[:billing_address] || options[:address]))
324
- avs_supported = AVS_SUPPORTED_COUNTRIES.include?(address[:country].to_s)
410
+ def add_soft_descriptors_from_hash(xml, soft_desc)
411
+ xml.tag! :SDMerchantName, soft_desc[:merchant_name] || nil
412
+ xml.tag! :SDProductDescription, soft_desc[:product_description] || nil
413
+ xml.tag! :SDMerchantCity, soft_desc[:merchant_city] || nil
414
+ xml.tag! :SDMerchantPhone, soft_desc[:merchant_phone] || nil
415
+ xml.tag! :SDMerchantURL, soft_desc[:merchant_url] || nil
416
+ xml.tag! :SDMerchantEmail, soft_desc[:merchant_email] || nil
417
+ end
325
418
 
326
- if avs_supported
327
- xml.tag! :AVSzip, (address[:zip] ? address[:zip].to_s[0..9] : nil)
328
- xml.tag! :AVSaddress1, (address[:address1] ? address[:address1][0..29] : nil)
329
- xml.tag! :AVSaddress2, (address[:address2] ? address[:address2][0..29] : nil)
330
- xml.tag! :AVScity, (address[:city] ? address[:city][0..19] : nil)
331
- xml.tag! :AVSstate, address[:state]
332
- xml.tag! :AVSphoneNum, (address[:phone] ? address[:phone].scan(/\d/).join.to_s[0..13] : nil)
333
- end
334
- # can't look in billing address?
335
- xml.tag! :AVSname, ((creditcard && creditcard.name) ? creditcard.name[0..29] : nil)
336
- xml.tag! :AVScountryCode, (avs_supported ? address[:country] : '')
419
+ def add_level2_tax(xml, options = {})
420
+ if (level2 = options[:level_2_data])
421
+ xml.tag! :TaxInd, level2[:tax_indicator] if [TAX_NOT_PROVIDED, TAX_INCLUDED, NON_TAXABLE_TRANSACTION].include?(level2[:tax_indicator].to_i)
422
+ xml.tag! :Tax, level2[:tax].to_i if level2[:tax]
423
+ end
424
+ end
337
425
 
338
- # Needs to come after AVScountryCode
339
- add_destination_address(xml, address) if avs_supported
426
+ def add_level3_tax(xml, options = {})
427
+ if (level3 = options[:level_3_data])
428
+ xml.tag! :PC3VATtaxAmt, byte_limit(level3[:vat_tax], 12) if level3[:vat_tax]
429
+ xml.tag! :PC3VATtaxRate, byte_limit(level3[:vat_rate], 4) if level3[:vat_rate]
430
+ xml.tag! :PC3AltTaxInd, byte_limit(level3[:alt_ind], 15) if level3[:alt_ind]
431
+ xml.tag! :PC3AltTaxAmt, byte_limit(level3[:alt_tax], 9) if level3[:alt_tax]
340
432
  end
341
433
  end
342
434
 
343
- def add_destination_address(xml, address)
344
- if address[:dest_zip]
345
- xml.tag! :AVSDestzip, (address[:dest_zip] ? address[:dest_zip].to_s[0..9] : nil)
346
- xml.tag! :AVSDestaddress1, (address[:dest_address1] ? address[:dest_address1][0..29] : nil)
347
- xml.tag! :AVSDestaddress2, (address[:dest_address2] ? address[:dest_address2][0..29] : nil)
348
- xml.tag! :AVSDestcity, (address[:dest_city] ? address[:dest_city][0..19] : nil)
349
- xml.tag! :AVSDeststate, address[:dest_state]
350
- xml.tag! :AVSDestphoneNum, (address[:dest_phone] ? address[:dest_phone].scan(/\d/).join.to_s[0..13] : nil)
435
+ def add_level2_advice_addendum(xml, options = {})
436
+ if (level2 = options[:level_2_data])
437
+ xml.tag! :AMEXTranAdvAddn1, byte_limit(level2[:advice_addendum_1], 40) if level2[:advice_addendum_1]
438
+ xml.tag! :AMEXTranAdvAddn2, byte_limit(level2[:advice_addendum_2], 40) if level2[:advice_addendum_2]
439
+ xml.tag! :AMEXTranAdvAddn3, byte_limit(level2[:advice_addendum_3], 40) if level2[:advice_addendum_3]
440
+ xml.tag! :AMEXTranAdvAddn4, byte_limit(level2[:advice_addendum_4], 40) if level2[:advice_addendum_4]
441
+ end
442
+ end
443
+
444
+ def add_level2_purchase(xml, options = {})
445
+ if (level2 = options[:level_2_data])
446
+ xml.tag! :PCOrderNum, byte_limit(level2[:purchase_order], 17) if level2[:purchase_order]
447
+ xml.tag! :PCDestZip, byte_limit(format_address_field(level2[:zip]), 10) if level2[:zip]
448
+ xml.tag! :PCDestName, byte_limit(format_address_field(level2[:name]), 30) if level2[:name]
449
+ xml.tag! :PCDestAddress1, byte_limit(format_address_field(level2[:address1]), 30) if level2[:address1]
450
+ xml.tag! :PCDestAddress2, byte_limit(format_address_field(level2[:address2]), 30) if level2[:address2]
451
+ xml.tag! :PCDestCity, byte_limit(format_address_field(level2[:city]), 20) if level2[:city]
452
+ xml.tag! :PCDestState, byte_limit(format_address_field(level2[:state]), 2) if level2[:state]
453
+ end
454
+ end
455
+
456
+ def add_level3_purchase(xml, options = {})
457
+ if (level3 = options[:level_3_data])
458
+ xml.tag! :PC3FreightAmt, byte_limit(level3[:freight_amount], 12) if level3[:freight_amount]
459
+ xml.tag! :PC3DutyAmt, byte_limit(level3[:duty_amount], 12) if level3[:duty_amount]
460
+ xml.tag! :PC3DestCountryCd, byte_limit(level3[:dest_country], 3) if level3[:dest_country]
461
+ xml.tag! :PC3ShipFromZip, byte_limit(level3[:ship_from_zip], 10) if level3[:ship_from_zip]
462
+ xml.tag! :PC3DiscAmt, byte_limit(level3[:discount_amount], 12) if level3[:discount_amount]
463
+ end
464
+ end
351
465
 
352
- xml.tag! :AVSDestname, (address[:dest_name] ? address[:dest_name][0..29] : nil)
353
- xml.tag! :AVSDestcountryCode, address[:dest_country]
466
+ def add_line_items(xml, options = {})
467
+ xml.tag! :PC3LineItemCount, byte_limit(options[:line_items].count, 2)
468
+ xml.tag! :PC3LineItemArray do
469
+ options[:line_items].each_with_index do |line_item, index|
470
+ xml.tag! :PC3LineItem do
471
+ xml.tag! :PC3DtlIndex, byte_limit(index + 1, 2)
472
+ line_item.each do |key, value|
473
+ if [:line_tot, 'line_tot'].include? key
474
+ formatted_key = :PC3Dtllinetot
475
+ else
476
+ formatted_key = "PC3Dtl#{key.to_s.camelize}".to_sym
477
+ end
478
+ xml.tag! formatted_key, value
479
+ end
480
+ end
481
+ end
354
482
  end
355
483
  end
356
484
 
485
+ #=====ADDRESS FIELDS=====
486
+
487
+ def add_address(xml, payment_source, options)
488
+ return unless (address = get_address(options))
489
+
490
+ if avs_supported?(address[:country]) || empty?(address[:country])
491
+ xml.tag! :AVSzip, byte_limit(format_address_field(address[:zip]), 10)
492
+ xml.tag! :AVSaddress1, byte_limit(format_address_field(address[:address1]), 30)
493
+ xml.tag! :AVSaddress2, byte_limit(format_address_field(address[:address2]), 30)
494
+ xml.tag! :AVScity, byte_limit(format_address_field(address[:city]), 20)
495
+ xml.tag! :AVSstate, byte_limit(format_address_field(address[:state]), 2)
496
+ xml.tag! :AVSphoneNum, (address[:phone] ? address[:phone].scan(/\d/).join.to_s[0..13] : nil)
497
+ end
498
+
499
+ xml.tag! :AVSname, billing_name(payment_source, options)
500
+ xml.tag! :AVScountryCode, byte_limit(format_address_field(filter_unsupported_countries(address[:country])), 2)
501
+
502
+ # Needs to come after AVScountryCode
503
+ add_destination_address(xml, address) if avs_supported?(address[:country]) || empty?(address[:country])
504
+ end
505
+
506
+ def add_destination_address(xml, address)
507
+ return unless address[:dest_zip]
508
+
509
+ xml.tag! :AVSDestzip, byte_limit(format_address_field(address[:dest_zip]), 10)
510
+ xml.tag! :AVSDestaddress1, byte_limit(format_address_field(address[:dest_address1]), 30)
511
+ xml.tag! :AVSDestaddress2, byte_limit(format_address_field(address[:dest_address2]), 30)
512
+ xml.tag! :AVSDestcity, byte_limit(format_address_field(address[:dest_city]), 20)
513
+ xml.tag! :AVSDeststate, byte_limit(format_address_field(address[:dest_state]), 2)
514
+ xml.tag! :AVSDestphoneNum, (address[:dest_phone] ? address[:dest_phone].scan(/\d/).join.to_s[0..13] : nil)
515
+ xml.tag! :AVSDestname, byte_limit(address[:dest_name], 30)
516
+ xml.tag! :AVSDestcountryCode, filter_unsupported_countries(address[:dest_country])
517
+ end
518
+
357
519
  # For Profile requests
358
520
  def add_customer_address(xml, options)
359
- if(address = (options[:billing_address] || options[:address]))
360
- xml.tag! :CustomerAddress1, (address[:address1] ? address[:address1][0..29] : nil)
361
- xml.tag! :CustomerAddress2, (address[:address2] ? address[:address2][0..29] : nil)
362
- xml.tag! :CustomerCity, (address[:city] ? address[:city][0..19] : nil)
363
- xml.tag! :CustomerState, address[:state]
364
- xml.tag! :CustomerZIP, (address[:zip] ? address[:zip].to_s[0..9] : nil)
365
- xml.tag! :CustomerEmail, address[:email].to_s[0..49] if address[:email]
366
- xml.tag! :CustomerPhone, (address[:phone] ? address[:phone].scan(/\d/).join.to_s : nil)
367
- xml.tag! :CustomerCountryCode, (address[:country] ? address[:country][0..1] : nil)
368
- end
521
+ return unless (address = get_address(options))
522
+
523
+ xml.tag! :CustomerAddress1, byte_limit(format_address_field(address[:address1]), 30)
524
+ xml.tag! :CustomerAddress2, byte_limit(format_address_field(address[:address2]), 30)
525
+ xml.tag! :CustomerCity, byte_limit(format_address_field(address[:city]), 20)
526
+ xml.tag! :CustomerState, byte_limit(format_address_field(address[:state]), 2)
527
+ xml.tag! :CustomerZIP, byte_limit(format_address_field(address[:zip]), 10)
528
+ xml.tag! :CustomerEmail, byte_limit(address[:email], 50) if address[:email]
529
+ xml.tag! :CustomerPhone, (address[:phone] ? address[:phone].scan(/\d/).join.to_s : nil)
530
+ xml.tag! :CustomerCountryCode, filter_unsupported_countries(address[:country])
369
531
  end
370
532
 
371
- def add_creditcard(xml, creditcard, currency=nil)
372
- unless creditcard.nil?
373
- xml.tag! :AccountNum, creditcard.number
374
- xml.tag! :Exp, expiry_date(creditcard)
533
+ def billing_name(payment_source, options)
534
+ if payment_source&.name.present?
535
+ payment_source.name[0..29]
536
+ elsif options[:billing_address][:name].present?
537
+ options[:billing_address][:name][0..29]
375
538
  end
539
+ end
376
540
 
377
- xml.tag! :CurrencyCode, currency_code(currency)
378
- xml.tag! :CurrencyExponent, currency_exponents(currency)
541
+ def avs_supported?(address)
542
+ AVS_SUPPORTED_COUNTRIES.include?(address.to_s)
543
+ end
544
+
545
+ def filter_unsupported_countries(address)
546
+ avs_supported?(address) ? address.to_s : ''
547
+ end
548
+
549
+ def get_address(options)
550
+ options[:billing_address] || options[:address]
551
+ end
552
+
553
+ #=====PAYMENT SOURCE FIELDS=====
554
+
555
+ # Payment can be done through either Credit Card or Electronic Check
556
+ def add_payment_source(xml, payment_source, options = {})
557
+ payment_source.is_a?(Check) ? add_echeck(xml, payment_source, options) : add_credit_card(xml, payment_source, options)
558
+ end
559
+
560
+ def add_echeck(xml, check, options = {})
561
+ return unless check
562
+
563
+ xml.tag! :CardBrand, 'EC'
564
+ add_currency_fields(xml, options[:currency])
565
+ xml.tag! :BCRtNum, check.routing_number
566
+ xml.tag! :CheckDDA, check.account_number if check.account_number
567
+ xml.tag! :BankAccountType, ACCOUNT_TYPE[check.account_type] if ACCOUNT_TYPE[check.account_type]
568
+ xml.tag! :ECPAuthMethod, options[:auth_method] if options[:auth_method]
569
+ xml.tag! :BankPmtDelv, options[:payment_delivery] || 'B'
570
+ xml.tag! :AVSname, (check&.name ? check.name[0..29] : nil) if get_address(options).blank?
571
+ end
572
+
573
+ def add_credit_card(xml, credit_card, options)
574
+ xml.tag! :AccountNum, credit_card.number if credit_card
575
+ xml.tag! :Exp, expiry_date(credit_card) if credit_card
576
+ add_currency_fields(xml, options[:currency])
577
+ add_verification_value(xml, credit_card) if credit_card
578
+ end
579
+
580
+ def add_refund_payment_source(xml, currency = nil)
581
+ xml.tag! :AccountNum, nil
582
+
583
+ add_currency_fields(xml, currency)
584
+ end
585
+
586
+ def add_verification_value(xml, credit_card)
587
+ return unless credit_card&.verification_value?
379
588
 
380
589
  # If you are trying to collect a Card Verification Number
381
590
  # (CardSecVal) for a Visa or Discover transaction, pass one of these values:
@@ -386,91 +595,288 @@ module ActiveMerchant #:nodoc:
386
595
  # Null-fill this attribute OR
387
596
  # Do not submit the attribute at all.
388
597
  # - http://download.chasepaymentech.com/docs/orbital/orbital_gateway_xml_specification.pdf
389
- unless creditcard.nil?
390
- if %w( visa discover ).include?(creditcard.brand)
391
- xml.tag! :CardSecValInd, (creditcard.verification_value? ? '1' : '9')
392
- end
393
- xml.tag! :CardSecVal, creditcard.verification_value if creditcard.verification_value?
394
- end
598
+ xml.tag! :CardSecValInd, '1' if %w(visa master discover).include?(credit_card.brand)
599
+ xml.tag! :CardSecVal, credit_card.verification_value
395
600
  end
396
601
 
397
- def add_refund(xml, currency=nil)
398
- xml.tag! :AccountNum, nil
399
-
602
+ def add_currency_fields(xml, currency)
400
603
  xml.tag! :CurrencyCode, currency_code(currency)
401
604
  xml.tag! :CurrencyExponent, currency_exponents(currency)
402
605
  end
403
606
 
404
- def add_managed_billing(xml, options)
405
- if mb = options[:managed_billing]
406
- ActiveMerchant.deprecated RECURRING_DEPRECATION_MESSAGE
407
-
408
- # default to recurring (R). Other option is deferred (D).
409
- xml.tag! :MBType, mb[:type] || RECURRING
410
- # default to Customer Reference Number
411
- xml.tag! :MBOrderIdGenerationMethod, mb[:order_id_generation_method] || 'IO'
412
- # By default use MBRecurringEndDate, set to N.
413
- # MMDDYYYY
414
- xml.tag! :MBRecurringStartDate, mb[:start_date].scan(/\d/).join.to_s if mb[:start_date]
415
- # MMDDYYYY
416
- xml.tag! :MBRecurringEndDate, mb[:end_date].scan(/\d/).join.to_s if mb[:end_date]
417
- # By default listen to any value set in MBRecurringEndDate.
418
- xml.tag! :MBRecurringNoEndDateFlag, mb[:no_end_date_flag] || 'N' # 'Y' || 'N' (Yes or No).
419
- xml.tag! :MBRecurringMaxBillings, mb[:max_billings] if mb[:max_billings]
420
- xml.tag! :MBRecurringFrequency, mb[:frequency] if mb[:frequency]
421
- xml.tag! :MBDeferredBillDate, mb[:deferred_bill_date] if mb[:deferred_bill_date]
422
- xml.tag! :MBMicroPaymentMaxDollarValue, mb[:max_dollar_value] if mb[:max_dollar_value]
423
- xml.tag! :MBMicroPaymentMaxBillingDays, mb[:max_billing_days] if mb[:max_billing_days]
424
- xml.tag! :MBMicroPaymentMaxTransactions, mb[:max_transactions] if mb[:max_transactions]
607
+ def add_card_indicators(xml, options)
608
+ xml.tag! :CardIndicators, options[:card_indicators] if options[:card_indicators]
609
+ end
610
+
611
+ def currency_code(currency)
612
+ CURRENCY_CODES[(currency || self.default_currency)].to_s
613
+ end
614
+
615
+ def currency_exponents(currency)
616
+ CURRENCY_EXPONENTS[(currency || self.default_currency)].to_s
617
+ end
618
+
619
+ def expiry_date(credit_card)
620
+ "#{format(credit_card.month, :two_digits)}#{format(credit_card.year, :two_digits)}"
621
+ end
622
+
623
+ def bin
624
+ @options[:bin] || (salem_mid? ? '000001' : '000002')
625
+ end
626
+
627
+ def salem_mid?
628
+ @options[:merchant_id].length == 6
629
+ end
630
+
631
+ #=====BRAND-SPECIFIC FIELDS=====
632
+
633
+ def add_cavv(xml, credit_card, three_d_secure)
634
+ return unless three_d_secure && credit_card.brand == 'visa'
635
+
636
+ xml.tag!(:CAVV, three_d_secure[:cavv])
637
+ end
638
+
639
+ def add_aav(xml, credit_card, three_d_secure)
640
+ return unless three_d_secure && credit_card.brand == 'master'
641
+
642
+ xml.tag!(:AAV, three_d_secure[:cavv])
643
+ end
644
+
645
+ def add_aevv(xml, credit_card, three_d_secure)
646
+ return unless three_d_secure && credit_card.brand == 'american_express'
647
+
648
+ xml.tag!(:AEVV, three_d_secure[:cavv])
649
+ end
650
+
651
+ def add_xid(xml, credit_card, three_d_secure)
652
+ return unless three_d_secure && credit_card.brand == 'visa'
653
+
654
+ xml.tag!(:XID, three_d_secure[:xid]) if three_d_secure[:xid]
655
+ end
656
+
657
+ def add_pymt_brand_program_code(xml, credit_card, three_d_secure)
658
+ return unless three_d_secure && credit_card.brand == 'american_express'
659
+
660
+ xml.tag!(:PymtBrandProgramCode, 'ASK')
661
+ end
662
+
663
+ def mastercard?(payment_source)
664
+ payment_source.is_a?(CreditCard) && payment_source.brand == 'master'
665
+ end
666
+
667
+ def add_mastercard_fields(xml, credit_card, parameters, three_d_secure)
668
+ add_mc_sca_merchant_initiated(xml, credit_card, parameters, three_d_secure)
669
+ add_mc_sca_recurring(xml, credit_card, parameters, three_d_secure)
670
+ add_mc_program_protocol(xml, credit_card, three_d_secure)
671
+ add_mc_directory_trans_id(xml, credit_card, three_d_secure)
672
+ add_mc_ucafind(xml, credit_card, three_d_secure)
673
+ end
674
+
675
+ def add_mc_sca_merchant_initiated(xml, credit_card, parameters, three_d_secure)
676
+ return unless parameters.try(:[], :sca_merchant_initiated)
677
+ return unless three_d_secure.try(:[], :eci) == '7'
678
+
679
+ xml.tag!(:SCAMerchantInitiatedTransaction, parameters[:sca_merchant_initiated])
680
+ end
681
+
682
+ def add_mc_sca_recurring(xml, credit_card, parameters, three_d_secure)
683
+ return unless parameters.try(:[], :sca_recurring)
684
+ return unless three_d_secure.try(:[], :eci) == '7'
685
+
686
+ xml.tag!(:SCARecurringPayment, parameters[:sca_recurring])
687
+ end
688
+
689
+ def add_mc_program_protocol(xml, credit_card, three_d_secure)
690
+ return unless version = three_d_secure.try(:[], :version)
691
+
692
+ xml.tag!(:MCProgramProtocol, version.to_s[0])
693
+ end
694
+
695
+ def add_mc_directory_trans_id(xml, credit_card, three_d_secure)
696
+ return unless three_d_secure
697
+
698
+ xml.tag!(:MCDirectoryTransID, three_d_secure[:ds_transaction_id]) if three_d_secure[:ds_transaction_id]
699
+ end
700
+
701
+ def add_mc_ucafind(xml, credit_card, three_d_secure)
702
+ return unless three_d_secure
703
+
704
+ xml.tag! :UCAFInd, '4'
705
+ end
706
+
707
+ #=====SCA (STORED CREDENTIAL) FIELDS=====
708
+
709
+ def add_stored_credentials(xml, parameters)
710
+ return unless parameters[:mit_stored_credential_ind] == 'Y' || parameters[:stored_credential] && !parameters[:stored_credential].values.all?(&:nil?)
711
+
712
+ if msg_type = get_msg_type(parameters)
713
+ xml.tag! :MITMsgType, msg_type
714
+ end
715
+ xml.tag! :MITStoredCredentialInd, 'Y'
716
+ if parameters[:mit_submitted_transaction_id]
717
+ xml.tag! :MITSubmittedTransactionID, parameters[:mit_submitted_transaction_id]
718
+ elsif parameters.dig(:stored_credential, :network_transaction_id) && parameters.dig(:stored_credential, :initiator) == 'merchant'
719
+ xml.tag! :MITSubmittedTransactionID, parameters[:stored_credential][:network_transaction_id]
425
720
  end
426
721
  end
427
722
 
428
- def parse(body)
429
- response = {}
430
- xml = REXML::Document.new(body)
431
- root = REXML::XPath.first(xml, "//Response") ||
432
- REXML::XPath.first(xml, "//ErrorResponse")
433
- if root
434
- root.elements.to_a.each do |node|
435
- recurring_parse_element(response, node)
723
+ def get_msg_type(parameters)
724
+ return parameters[:mit_msg_type] if parameters[:mit_msg_type]
725
+ return 'CSTO' if parameters[:stored_credential][:initial_transaction]
726
+ return unless parameters[:stored_credential][:initiator] && parameters[:stored_credential][:reason_type]
727
+
728
+ initiator =
729
+ case parameters[:stored_credential][:initiator]
730
+ when 'cardholder', 'customer' then 'C'
731
+ when 'merchant' then 'M'
436
732
  end
733
+ reason =
734
+ case parameters[:stored_credential][:reason_type]
735
+ when 'recurring' then 'REC'
736
+ when 'installment' then 'INS'
737
+ when 'unscheduled' then 'USE'
738
+ end
739
+
740
+ "#{initiator}#{reason}"
741
+ end
742
+
743
+ #=====NETWORK TOKENIZATION FIELDS=====
744
+
745
+ def add_eci(xml, credit_card, three_d_secure)
746
+ eci = if three_d_secure
747
+ three_d_secure[:eci]
748
+ elsif credit_card.is_a?(NetworkTokenizationCreditCard)
749
+ credit_card.eci
750
+ end
751
+
752
+ xml.tag!(:AuthenticationECIInd, eci) if eci
753
+ end
754
+
755
+ def add_dpanind(xml, credit_card)
756
+ return unless credit_card.is_a?(NetworkTokenizationCreditCard)
757
+
758
+ xml.tag! :DPANInd, 'Y'
759
+ end
760
+
761
+ def add_digital_token_cryptogram(xml, credit_card)
762
+ return unless credit_card.is_a?(NetworkTokenizationCreditCard)
763
+
764
+ xml.tag! :DigitalTokenCryptogram, credit_card.payment_cryptogram
765
+ end
766
+
767
+ #=====OTHER FIELDS=====
768
+
769
+ # For Canadian transactions on PNS Tampa on New Order
770
+ # RF - First Recurring Transaction
771
+ # RS - Subsequent Recurring Transactions
772
+ def set_recurring_ind(xml, parameters)
773
+ return unless parameters[:recurring_ind]
774
+ raise 'RecurringInd must be set to either "RF" or "RS"' unless %w(RF RS).include?(parameters[:recurring_ind])
775
+
776
+ xml.tag! :RecurringInd, parameters[:recurring_ind]
777
+ end
778
+
779
+ def add_managed_billing(xml, options)
780
+ return unless mb = options[:managed_billing]
781
+
782
+ ActiveMerchant.deprecated RECURRING_DEPRECATION_MESSAGE
783
+
784
+ # default to recurring (R). Other option is deferred (D).
785
+ xml.tag! :MBType, mb[:type] || RECURRING
786
+ # default to Customer Reference Number
787
+ xml.tag! :MBOrderIdGenerationMethod, mb[:order_id_generation_method] || 'IO'
788
+ # By default use MBRecurringEndDate, set to N.
789
+ # MMDDYYYY
790
+ xml.tag! :MBRecurringStartDate, mb[:start_date].scan(/\d/).join.to_s if mb[:start_date]
791
+ # MMDDYYYY
792
+ xml.tag! :MBRecurringEndDate, mb[:end_date].scan(/\d/).join.to_s if mb[:end_date]
793
+ # By default listen to any value set in MBRecurringEndDate.
794
+ xml.tag! :MBRecurringNoEndDateFlag, mb[:no_end_date_flag] || 'N' # 'Y' || 'N' (Yes or No).
795
+ xml.tag! :MBRecurringMaxBillings, mb[:max_billings] if mb[:max_billings]
796
+ xml.tag! :MBRecurringFrequency, mb[:frequency] if mb[:frequency]
797
+ xml.tag! :MBDeferredBillDate, mb[:deferred_bill_date] if mb[:deferred_bill_date]
798
+ xml.tag! :MBMicroPaymentMaxDollarValue, mb[:max_dollar_value] if mb[:max_dollar_value]
799
+ xml.tag! :MBMicroPaymentMaxBillingDays, mb[:max_billing_days] if mb[:max_billing_days]
800
+ xml.tag! :MBMicroPaymentMaxTransactions, mb[:max_transactions] if mb[:max_transactions]
801
+ end
802
+
803
+ def add_ews_details(xml, payment_source, parameters = {})
804
+ split_name = payment_source.first_name.split if payment_source.first_name
805
+ xml.tag! :EWSFirstName, split_name[0]
806
+ xml.tag! :EWSMiddleName, split_name[1..-1].join(' ')
807
+ xml.tag! :EWSLastName, payment_source.last_name
808
+ xml.tag! :EWSBusinessName, parameters[:company] if payment_source.first_name.empty? && payment_source.last_name.empty?
809
+
810
+ if (address = (parameters[:billing_address] || parameters[:address]))
811
+ xml.tag! :EWSAddressLine1, byte_limit(format_address_field(address[:address1]), 30)
812
+ xml.tag! :EWSAddressLine2, byte_limit(format_address_field(address[:address2]), 30)
813
+ xml.tag! :EWSCity, byte_limit(format_address_field(address[:city]), 20)
814
+ xml.tag! :EWSState, byte_limit(format_address_field(address[:state]), 2)
815
+ xml.tag! :EWSZip, byte_limit(format_address_field(address[:zip]), 10)
437
816
  end
438
817
 
439
- response.delete_if { |k,_| SENSITIVE_FIELDS.include?(k) }
818
+ xml.tag! :EWSPhoneType, parameters[:phone_type]
819
+ xml.tag! :EWSPhoneNumber, parameters[:phone_number]
820
+ xml.tag! :EWSCheckSerialNumber, payment_source.account_number unless parameters[:auth_method].eql?('I')
440
821
  end
441
822
 
442
- def recurring_parse_element(response, node)
443
- if node.has_elements?
444
- node.elements.each{|e| recurring_parse_element(response, e) }
445
- else
446
- response[node.name.underscore.to_sym] = node.text
823
+ # Adds ECP conditional attributes depending on other attribute values
824
+ def add_ecp_details(xml, payment_source, parameters = {})
825
+ requires!(payment_source.account_number) if parameters[:auth_method]&.eql?('A') || parameters[:auth_method]&.eql?('P')
826
+ xml.tag! :ECPActionCode, parameters[:action_code] if parameters[:action_code]
827
+ xml.tag! :ECPCheckSerialNumber, payment_source.account_number if parameters[:auth_method]&.eql?('A') || parameters[:auth_method]&.eql?('P')
828
+ if parameters[:auth_method]&.eql?('P')
829
+ xml.tag! :ECPTerminalCity, parameters[:terminal_city] if parameters[:terminal_city]
830
+ xml.tag! :ECPTerminalState, parameters[:terminal_state] if parameters[:terminal_state]
831
+ xml.tag! :ECPImageReferenceNumber, parameters[:image_reference_number] if parameters[:image_reference_number]
832
+ end
833
+ if parameters[:action_code]&.eql?('W3') || parameters[:action_code]&.eql?('W5') ||
834
+ parameters[:action_code]&.eql?('W7') || parameters[:action_code]&.eql?('W9')
835
+ add_ews_details(xml, payment_source, parameters)
447
836
  end
448
837
  end
449
838
 
450
- def commit(order, message_type, trace_number=nil)
451
- headers = POST_HEADERS.merge("Content-length" => order.size.to_s)
452
- headers.merge!( "Trace-number" => trace_number.to_s,
453
- "Merchant-Id" => @options[:merchant_id] ) if @options[:retry_logic] && trace_number
454
- request = lambda{|url| parse(ssl_post(url, order, headers))}
839
+ def add_xml_credentials(xml)
840
+ unless ip_authentication?
841
+ xml.tag! :OrbitalConnectionUsername, @options[:login]
842
+ xml.tag! :OrbitalConnectionPassword, @options[:password]
843
+ end
844
+ end
455
845
 
456
- # Failover URL will be attempted in the event of a connection error
457
- response = begin
458
- request.call(remote_url)
459
- rescue ConnectionError
460
- request.call(remote_url(:secondary))
846
+ def add_bin_merchant_and_terminal(xml, parameters)
847
+ xml.tag! :BIN, bin
848
+ xml.tag! :MerchantID, @options[:merchant_id]
849
+ xml.tag! :TerminalID, parameters[:terminal_id] || '001'
850
+ end
851
+
852
+ #=====REQUEST/RESPONSE METHODS=====
853
+
854
+ def commit(order, message_type, retry_logic = nil, trace_number = nil)
855
+ headers = POST_HEADERS.merge('Content-length' => order.size.to_s)
856
+ if (@options[:retry_logic] || retry_logic) && trace_number
857
+ headers['Trace-number'] = trace_number.to_s
858
+ headers['Merchant-Id'] = @options[:merchant_id]
461
859
  end
860
+ request = ->(url) { parse(ssl_post(url, order, headers)) }
861
+
862
+ # Failover URL will be attempted in the event of a connection error
863
+ response =
864
+ begin
865
+ request.call(remote_url)
866
+ rescue ConnectionError
867
+ request.call(remote_url(:secondary))
868
+ end
462
869
 
463
870
  Response.new(success?(response, message_type), message_from(response), response,
464
871
  {
465
- :authorization => authorization_string(response[:tx_ref_num], response[:order_id]),
466
- :test => self.test?,
467
- :avs_result => OrbitalGateway::AVSResult.new(response[:avs_resp_code]),
468
- :cvv_result => OrbitalGateway::CVVResult.new(response[:cvv2_resp_code])
469
- }
470
- )
872
+ authorization: authorization_string(response[:tx_ref_num], response[:order_id]),
873
+ test: self.test?,
874
+ avs_result: OrbitalGateway::AVSResult.new(response[:avs_resp_code]),
875
+ cvv_result: OrbitalGateway::CVVResult.new(response[:cvv2_resp_code])
876
+ })
471
877
  end
472
878
 
473
- def remote_url(url=:primary)
879
+ def remote_url(url = :primary)
474
880
  if url == :primary
475
881
  (self.test? ? self.test_url : self.live_url)
476
882
  else
@@ -478,14 +884,38 @@ module ActiveMerchant #:nodoc:
478
884
  end
479
885
  end
480
886
 
887
+ def parse(body)
888
+ response = {}
889
+ xml = REXML::Document.new(strip_invalid_xml_chars(body))
890
+ root = REXML::XPath.first(xml, '//Response') ||
891
+ REXML::XPath.first(xml, '//ErrorResponse')
892
+ if root
893
+ root.elements.to_a.each do |node|
894
+ recurring_parse_element(response, node)
895
+ end
896
+ end
897
+
898
+ response.delete_if { |k, _| SENSITIVE_FIELDS.include?(k) }
899
+ end
900
+
901
+ def recurring_parse_element(response, node)
902
+ if node.has_elements?
903
+ node.elements.each { |e| recurring_parse_element(response, e) }
904
+ else
905
+ response[node.name.underscore.to_sym] = node.text
906
+ end
907
+ end
908
+
481
909
  def success?(response, message_type)
482
- if [:refund, :void].include?(message_type)
910
+ if %i[void].include?(message_type)
483
911
  response[:proc_status] == SUCCESS
912
+ elsif %i[refund].include?(message_type)
913
+ response[:proc_status] == SUCCESS && response[:approval_status] == APPROVAL_SUCCESS
484
914
  elsif response[:customer_profile_action]
485
915
  response[:profile_proc_status] == SUCCESS
486
916
  else
487
917
  response[:proc_status] == SUCCESS &&
488
- APPROVED.include?(response[:resp_code])
918
+ APPROVED.include?(response[:resp_code])
489
919
  end
490
920
  end
491
921
 
@@ -497,61 +927,73 @@ module ActiveMerchant #:nodoc:
497
927
  @options[:ip_authentication] == true
498
928
  end
499
929
 
500
- def build_new_order_xml(action, money, parameters = {})
930
+ #=====BUILDER METHODS=====
931
+
932
+ def build_new_auth_purchase_order(action, money, payment_source, options)
933
+ build_new_order_xml(action, money, payment_source, options) do |xml|
934
+ add_payment_source(xml, payment_source, options)
935
+ add_address(xml, payment_source, options)
936
+ if @options[:customer_profiles]
937
+ add_customer_data(xml, payment_source, options)
938
+ add_managed_billing(xml, options)
939
+ end
940
+ end
941
+ end
942
+
943
+ def build_new_order_xml(action, money, payment_source, parameters = {})
501
944
  requires!(parameters, :order_id)
502
945
  xml = xml_envelope
503
946
  xml.tag! :Request do
504
947
  xml.tag! :NewOrder do
505
948
  add_xml_credentials(xml)
506
- # EC - Ecommerce transaction
507
- # RC - Recurring Payment transaction
508
- # MO - Mail Order Telephone Order transaction
509
- # IV - Interactive Voice Response
510
- # IN - Interactive Voice Response
511
949
  xml.tag! :IndustryType, parameters[:industry_type] || ECOMMERCE_TRANSACTION
512
- # A - Auth Only No Capture
513
- # AC - Auth and Capture
514
- # F - Force Auth No Capture and no online authorization
515
- # FR - Force Auth No Capture and no online authorization
516
- # FC - Force Auth and Capture no online authorization
517
- # R - Refund and Capture no online authorization
518
950
  xml.tag! :MessageType, action
519
951
  add_bin_merchant_and_terminal(xml, parameters)
520
952
 
521
953
  yield xml if block_given?
522
954
 
955
+ three_d_secure = parameters[:three_d_secure]
956
+
957
+ add_eci(xml, payment_source, three_d_secure)
958
+ add_cavv(xml, payment_source, three_d_secure)
959
+ add_xid(xml, payment_source, three_d_secure)
960
+
523
961
  xml.tag! :OrderID, format_order_id(parameters[:order_id])
524
962
  xml.tag! :Amount, amount(money)
525
963
  xml.tag! :Comments, parameters[:comments] if parameters[:comments]
526
964
 
965
+ add_level2_tax(xml, parameters)
966
+ add_level2_advice_addendum(xml, parameters)
967
+
968
+ add_aav(xml, payment_source, three_d_secure)
527
969
  # CustomerAni, AVSPhoneType and AVSDestPhoneType could be added here.
528
970
 
529
- if parameters[:soft_descriptors].is_a?(OrbitalSoftDescriptors)
530
- add_soft_descriptors(xml, parameters[:soft_descriptors])
531
- end
971
+ add_soft_descriptors(xml, parameters[:soft_descriptors])
972
+ add_dpanind(xml, payment_source)
973
+ add_aevv(xml, payment_source, three_d_secure)
974
+ add_digital_token_cryptogram(xml, payment_source)
975
+
976
+ xml.tag! :ECPSameDayInd, parameters[:same_day] if parameters[:same_day] && payment_source.is_a?(Check)
532
977
 
533
978
  set_recurring_ind(xml, parameters)
534
979
 
535
980
  # Append Transaction Reference Number at the end for Refund transactions
536
- if action == REFUND
537
- tx_ref_num, _ = split_authorization(parameters[:authorization])
538
- xml.tag! :TxRefNum, tx_ref_num
539
- end
981
+ add_tx_ref_num(xml, parameters[:authorization]) if action == REFUND
982
+
983
+ add_level2_purchase(xml, parameters)
984
+ add_level3_purchase(xml, parameters)
985
+ add_level3_tax(xml, parameters)
986
+ add_line_items(xml, parameters) if parameters[:line_items]
987
+ add_ecp_details(xml, payment_source, parameters) if payment_source.is_a?(Check)
988
+ add_card_indicators(xml, parameters)
989
+ add_stored_credentials(xml, parameters)
990
+ add_pymt_brand_program_code(xml, payment_source, three_d_secure)
991
+ add_mastercard_fields(xml, payment_source, parameters, three_d_secure) if mastercard?(payment_source)
540
992
  end
541
993
  end
542
994
  xml.target!
543
995
  end
544
996
 
545
- # For Canadian transactions on PNS Tampa on New Order
546
- # RF - First Recurring Transaction
547
- # RS - Subsequent Recurring Transactions
548
- def set_recurring_ind(xml, parameters)
549
- if parameters[:recurring_ind]
550
- raise "RecurringInd must be set to either \"RF\" or \"RS\"" unless %w(RF RS).include?(parameters[:recurring_ind])
551
- xml.tag! :RecurringInd, parameters[:recurring_ind]
552
- end
553
- end
554
-
555
997
  def build_mark_for_capture_xml(money, authorization, parameters = {})
556
998
  tx_ref_num, order_id = split_authorization(authorization)
557
999
  xml = xml_envelope
@@ -560,8 +1002,14 @@ module ActiveMerchant #:nodoc:
560
1002
  add_xml_credentials(xml)
561
1003
  xml.tag! :OrderID, format_order_id(order_id)
562
1004
  xml.tag! :Amount, amount(money)
1005
+ add_level2_tax(xml, parameters)
563
1006
  add_bin_merchant_and_terminal(xml, parameters)
564
1007
  xml.tag! :TxRefNum, tx_ref_num
1008
+ add_level2_purchase(xml, parameters)
1009
+ add_level2_advice_addendum(xml, parameters)
1010
+ add_level3_purchase(xml, parameters)
1011
+ add_level3_tax(xml, parameters)
1012
+ add_line_items(xml, parameters) if parameters[:line_items]
565
1013
  end
566
1014
  end
567
1015
  xml.target!
@@ -585,43 +1033,16 @@ module ActiveMerchant #:nodoc:
585
1033
  xml.target!
586
1034
  end
587
1035
 
588
- def currency_code(currency)
589
- CURRENCY_CODES[(currency || self.default_currency)].to_s
590
- end
591
-
592
- def currency_exponents(currency)
593
- CURRENCY_EXPONENTS[(currency || self.default_currency)].to_s
594
- end
595
-
596
- def expiry_date(credit_card)
597
- "#{format(credit_card.month, :two_digits)}#{format(credit_card.year, :two_digits)}"
598
- end
599
-
600
- def bin
601
- @options[:bin] || (salem_mid? ? '000001' : '000002')
602
- end
603
-
604
1036
  def xml_envelope
605
- xml = Builder::XmlMarkup.new(:indent => 2)
606
- xml.instruct!(:xml, :version => '1.0', :encoding => 'UTF-8')
1037
+ xml = Builder::XmlMarkup.new(indent: 2)
1038
+ xml.instruct!(:xml, version: '1.0', encoding: 'UTF-8')
607
1039
  xml
608
1040
  end
609
1041
 
610
- def add_xml_credentials(xml)
611
- unless ip_authentication?
612
- xml.tag! :OrbitalConnectionUsername, @options[:login]
613
- xml.tag! :OrbitalConnectionPassword, @options[:password]
614
- end
615
- end
616
-
617
- def add_bin_merchant_and_terminal(xml, parameters)
618
- xml.tag! :BIN, bin
619
- xml.tag! :MerchantID, @options[:merchant_id]
620
- xml.tag! :TerminalID, parameters[:terminal_id] || '001'
621
- end
622
-
623
- def salem_mid?
624
- @options[:merchant_id].length == 6
1042
+ # Null characters are possible in some responses (namely, the respMsg field), causing XML parsing errors
1043
+ # Prevent by substituting these with a valid placeholder string
1044
+ def strip_invalid_xml_chars(xml)
1045
+ xml.gsub(/\u0000/, '[null]')
625
1046
  end
626
1047
 
627
1048
  # The valid characters include:
@@ -630,13 +1051,35 @@ module ActiveMerchant #:nodoc:
630
1051
  # 2. - , $ @ & and a space character, though the space character cannot be the leading character
631
1052
  # 3. PINless Debit transactions can only use uppercase and lowercase alpha (A-Z, a-z) and numeric (0-9)
632
1053
  def format_order_id(order_id)
633
- illegal_characters = /[^,$@\- \w]/
634
- order_id = order_id.to_s.gsub(/\./, '-')
1054
+ illegal_characters = /[^,$@&\- \w]/
1055
+ order_id = order_id.to_s.tr('.', '-')
635
1056
  order_id.gsub!(illegal_characters, '')
1057
+ order_id.lstrip!
636
1058
  order_id[0...22]
637
1059
  end
638
1060
 
639
- def build_customer_request_xml(creditcard, options = {})
1061
+ # Address-related fields cannot contain % | ^ \ /
1062
+ # Returns the value with these characters removed, or nil
1063
+ def format_address_field(value)
1064
+ value.gsub(/[%\|\^\\\/]/, '') if value.respond_to?(:gsub)
1065
+ end
1066
+
1067
+ # Field lengths should be limited by byte count instead of character count
1068
+ # Returns the truncated value or nil
1069
+ def byte_limit(value, byte_length)
1070
+ limited_value = ''
1071
+
1072
+ value.to_s.each_char do |c|
1073
+ break if (limited_value.bytesize + c.bytesize) > byte_length
1074
+
1075
+ limited_value << c
1076
+ end
1077
+
1078
+ limited_value
1079
+ end
1080
+
1081
+ def build_customer_request_xml(credit_card, options = {})
1082
+ ActiveMerchant.deprecated 'Customer Profile support in Orbital is non-conformant to the ActiveMerchant API and will be removed in its current form in a future version. Please contact the ActiveMerchant maintainers if you have an interest in modifying it to conform to the store/unstore/update API.'
640
1083
  xml = xml_envelope
641
1084
  xml.tag! :Request do
642
1085
  xml.tag! :Profile do
@@ -644,7 +1087,7 @@ module ActiveMerchant #:nodoc:
644
1087
  xml.tag! :OrbitalConnectionPassword, @options[:password] unless ip_authentication?
645
1088
  xml.tag! :CustomerBin, bin
646
1089
  xml.tag! :CustomerMerchantID, @options[:merchant_id]
647
- xml.tag! :CustomerName, creditcard.name if creditcard
1090
+ xml.tag! :CustomerName, credit_card.name if credit_card
648
1091
  xml.tag! :CustomerRefNum, options[:customer_ref_num] if options[:customer_ref_num]
649
1092
 
650
1093
  add_customer_address(xml, options)
@@ -672,8 +1115,8 @@ module ActiveMerchant #:nodoc:
672
1115
  xml.tag! :Status, options[:status] || ACTIVE # Active
673
1116
  end
674
1117
 
675
- xml.tag! :CCAccountNum, creditcard.number if creditcard
676
- xml.tag! :CCExpireDate, creditcard.expiry_date.expiration.strftime("%m%y") if creditcard
1118
+ xml.tag! :CCAccountNum, credit_card.number if credit_card
1119
+ xml.tag! :CCExpireDate, credit_card.expiry_date.expiration.strftime('%m%y') if credit_card
677
1120
 
678
1121
  # This has to come after CCExpireDate.
679
1122
  add_managed_billing(xml, options)
@@ -691,55 +1134,55 @@ module ActiveMerchant #:nodoc:
691
1134
  #
692
1135
  class AVSResult < ActiveMerchant::Billing::AVSResult
693
1136
  CODES = {
694
- '1' => 'No address supplied',
695
- '2' => 'Bill-to address did not pass Auth Host edit checks',
696
- '3' => 'AVS not performed',
697
- '4' => 'Issuer does not participate in AVS',
698
- '5' => 'Edit-error - AVS data is invalid',
699
- '6' => 'System unavailable or time-out',
700
- '7' => 'Address information unavailable',
701
- '8' => 'Transaction Ineligible for AVS',
702
- '9' => 'Zip Match/Zip 4 Match/Locale match',
703
- 'A' => 'Zip Match/Zip 4 Match/Locale no match',
704
- 'B' => 'Zip Match/Zip 4 no Match/Locale match',
705
- 'C' => 'Zip Match/Zip 4 no Match/Locale no match',
706
- 'D' => 'Zip No Match/Zip 4 Match/Locale match',
707
- 'E' => 'Zip No Match/Zip 4 Match/Locale no match',
708
- 'F' => 'Zip No Match/Zip 4 No Match/Locale match',
709
- 'G' => 'No match at all',
710
- 'H' => 'Zip Match/Locale match',
711
- 'J' => 'Issuer does not participate in Global AVS',
712
- 'JA' => 'International street address and postal match',
713
- 'JB' => 'International street address match. Postal code not verified',
714
- 'JC' => 'International street address and postal code not verified',
715
- 'JD' => 'International postal code match. Street address not verified',
716
- 'M1' => 'Cardholder name matches',
717
- 'M2' => 'Cardholder name, billing address, and postal code matches',
718
- 'M3' => 'Cardholder name and billing code matches',
719
- 'M4' => 'Cardholder name and billing address match',
720
- 'M5' => 'Cardholder name incorrect, billing address and postal code match',
721
- 'M6' => 'Cardholder name incorrect, billing postal code matches',
722
- 'M7' => 'Cardholder name incorrect, billing address matches',
723
- 'M8' => 'Cardholder name, billing address and postal code are all incorrect',
724
- 'N3' => 'Address matches, ZIP not verified',
725
- 'N4' => 'Address and ZIP code not verified due to incompatible formats',
726
- 'N5' => 'Address and ZIP code match (International only)',
727
- 'N6' => 'Address not verified (International only)',
728
- 'N7' => 'ZIP matches, address not verified',
729
- 'N8' => 'Address and ZIP code match (International only)',
730
- 'N9' => 'Address and ZIP code match (UK only)',
731
- 'R' => 'Issuer does not participate in AVS',
732
- 'UK' => 'Unknown',
733
- 'X' => 'Zip Match/Zip 4 Match/Address Match',
734
- 'Z' => 'Zip Match/Locale no match',
1137
+ '1' => 'No address supplied',
1138
+ '2' => 'Bill-to address did not pass Auth Host edit checks',
1139
+ '3' => 'AVS not performed',
1140
+ '4' => 'Issuer does not participate in AVS',
1141
+ '5' => 'Edit-error - AVS data is invalid',
1142
+ '6' => 'System unavailable or time-out',
1143
+ '7' => 'Address information unavailable',
1144
+ '8' => 'Transaction Ineligible for AVS',
1145
+ '9' => 'Zip Match/Zip 4 Match/Locale match',
1146
+ 'A' => 'Zip Match/Zip 4 Match/Locale no match',
1147
+ 'B' => 'Zip Match/Zip 4 no Match/Locale match',
1148
+ 'C' => 'Zip Match/Zip 4 no Match/Locale no match',
1149
+ 'D' => 'Zip No Match/Zip 4 Match/Locale match',
1150
+ 'E' => 'Zip No Match/Zip 4 Match/Locale no match',
1151
+ 'F' => 'Zip No Match/Zip 4 No Match/Locale match',
1152
+ 'G' => 'No match at all',
1153
+ 'H' => 'Zip Match/Locale match',
1154
+ 'J' => 'Issuer does not participate in Global AVS',
1155
+ 'JA' => 'International street address and postal match',
1156
+ 'JB' => 'International street address match. Postal code not verified',
1157
+ 'JC' => 'International street address and postal code not verified',
1158
+ 'JD' => 'International postal code match. Street address not verified',
1159
+ 'M1' => 'Cardholder name matches',
1160
+ 'M2' => 'Cardholder name, billing address, and postal code matches',
1161
+ 'M3' => 'Cardholder name and billing code matches',
1162
+ 'M4' => 'Cardholder name and billing address match',
1163
+ 'M5' => 'Cardholder name incorrect, billing address and postal code match',
1164
+ 'M6' => 'Cardholder name incorrect, billing postal code matches',
1165
+ 'M7' => 'Cardholder name incorrect, billing address matches',
1166
+ 'M8' => 'Cardholder name, billing address and postal code are all incorrect',
1167
+ 'N3' => 'Address matches, ZIP not verified',
1168
+ 'N4' => 'Address and ZIP code not verified due to incompatible formats',
1169
+ 'N5' => 'Address and ZIP code match (International only)',
1170
+ 'N6' => 'Address not verified (International only)',
1171
+ 'N7' => 'ZIP matches, address not verified',
1172
+ 'N8' => 'Address and ZIP code match (International only)',
1173
+ 'N9' => 'Address and ZIP code match (UK only)',
1174
+ 'R' => 'Issuer does not participate in AVS',
1175
+ 'UK' => 'Unknown',
1176
+ 'X' => 'Zip Match/Zip 4 Match/Address Match',
1177
+ 'Z' => 'Zip Match/Locale no match'
735
1178
  }
736
1179
 
737
1180
  # Map vendor's AVS result code to a postal match code
738
1181
  ORBITAL_POSTAL_MATCH_CODE = {
739
- 'Y' => %w( 9 A B C H JA JD M2 M3 M5 N5 N8 N9 X Z ),
740
- 'N' => %w( D E F G M8 ),
741
- 'X' => %w( 4 J R ),
742
- nil => %w( 1 2 3 5 6 7 8 JB JC M1 M4 M6 M7 N3 N4 N6 N7 UK )
1182
+ 'Y' => %w(9 A B C H JA JD M2 M3 M5 N5 N8 N9 X Z),
1183
+ 'N' => %w(D E F G M8),
1184
+ 'X' => %w(4 J R),
1185
+ nil => %w(1 2 3 5 6 7 8 JB JC M1 M4 M6 M7 N3 N4 N6 N7 UK)
743
1186
  }.inject({}) do |map, (type, codes)|
744
1187
  codes.each { |code| map[code] = type }
745
1188
  map
@@ -747,10 +1190,10 @@ module ActiveMerchant #:nodoc:
747
1190
 
748
1191
  # Map vendor's AVS result code to a street match code
749
1192
  ORBITAL_STREET_MATCH_CODE = {
750
- 'Y' => %w( 9 B D F H JA JB M2 M4 M5 M6 M7 N3 N5 N7 N8 N9 X ),
751
- 'N' => %w( A C E G M8 Z ),
752
- 'X' => %w( 4 J R ),
753
- nil => %w( 1 2 3 5 6 7 8 JC JD M1 M3 N4 N6 UK )
1193
+ 'Y' => %w(9 B D F H JA JB M2 M4 M5 M6 M7 N3 N5 N7 N8 N9 X),
1194
+ 'N' => %w(A C E G M8 Z),
1195
+ 'X' => %w(4 J R),
1196
+ nil => %w(1 2 3 5 6 7 8 JC JD M1 M3 N4 N6 UK)
754
1197
  }.inject({}) do |map, (type, codes)|
755
1198
  codes.each { |code| map[code] = type }
756
1199
  map