activemerchant 1.100.0 → 1.133.0

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