swiss-activemerchant 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (287) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG +4033 -0
  3. data/CONTRIBUTORS +568 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.md +249 -0
  6. data/lib/active_merchant/billing/apple_pay_payment_token.rb +22 -0
  7. data/lib/active_merchant/billing/avs_result.rb +95 -0
  8. data/lib/active_merchant/billing/base.rb +48 -0
  9. data/lib/active_merchant/billing/check.rb +112 -0
  10. data/lib/active_merchant/billing/compatibility.rb +118 -0
  11. data/lib/active_merchant/billing/credit_card.rb +451 -0
  12. data/lib/active_merchant/billing/credit_card_formatting.rb +24 -0
  13. data/lib/active_merchant/billing/credit_card_methods.rb +512 -0
  14. data/lib/active_merchant/billing/cvv_result.rb +37 -0
  15. data/lib/active_merchant/billing/gateway.rb +332 -0
  16. data/lib/active_merchant/billing/gateways/adyen.rb +774 -0
  17. data/lib/active_merchant/billing/gateways/airwallex.rb +370 -0
  18. data/lib/active_merchant/billing/gateways/alelo.rb +256 -0
  19. data/lib/active_merchant/billing/gateways/allied_wallet.rb +205 -0
  20. data/lib/active_merchant/billing/gateways/authorize_net.rb +1125 -0
  21. data/lib/active_merchant/billing/gateways/authorize_net_arb.rb +424 -0
  22. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +977 -0
  23. data/lib/active_merchant/billing/gateways/axcessms.rb +243 -0
  24. data/lib/active_merchant/billing/gateways/balanced.rb +263 -0
  25. data/lib/active_merchant/billing/gateways/bambora_apac.rb +222 -0
  26. data/lib/active_merchant/billing/gateways/bank_frick.rb +225 -0
  27. data/lib/active_merchant/billing/gateways/banwire.rb +116 -0
  28. data/lib/active_merchant/billing/gateways/barclaycard_smartpay.rb +397 -0
  29. data/lib/active_merchant/billing/gateways/barclays_epdq_extra_plus.rb +15 -0
  30. data/lib/active_merchant/billing/gateways/be2bill.rb +131 -0
  31. data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +474 -0
  32. data/lib/active_merchant/billing/gateways/beanstream.rb +238 -0
  33. data/lib/active_merchant/billing/gateways/beanstream_interac.rb +57 -0
  34. data/lib/active_merchant/billing/gateways/blue_pay.rb +549 -0
  35. data/lib/active_merchant/billing/gateways/blue_snap.rb +644 -0
  36. data/lib/active_merchant/billing/gateways/bogus.rb +190 -0
  37. data/lib/active_merchant/billing/gateways/borgun.rb +272 -0
  38. data/lib/active_merchant/billing/gateways/bpoint.rb +277 -0
  39. data/lib/active_merchant/billing/gateways/braintree/braintree_common.rb +28 -0
  40. data/lib/active_merchant/billing/gateways/braintree/token_nonce.rb +113 -0
  41. data/lib/active_merchant/billing/gateways/braintree.rb +19 -0
  42. data/lib/active_merchant/billing/gateways/braintree_blue.rb +952 -0
  43. data/lib/active_merchant/billing/gateways/braintree_orange.rb +19 -0
  44. data/lib/active_merchant/billing/gateways/bridge_pay.rb +244 -0
  45. data/lib/active_merchant/billing/gateways/cams.rb +230 -0
  46. data/lib/active_merchant/billing/gateways/card_connect.rb +338 -0
  47. data/lib/active_merchant/billing/gateways/card_save.rb +21 -0
  48. data/lib/active_merchant/billing/gateways/card_stream.rb +394 -0
  49. data/lib/active_merchant/billing/gateways/cardknox.rb +327 -0
  50. data/lib/active_merchant/billing/gateways/cardprocess.rb +256 -0
  51. data/lib/active_merchant/billing/gateways/cashnet.rb +235 -0
  52. data/lib/active_merchant/billing/gateways/cc5.rb +198 -0
  53. data/lib/active_merchant/billing/gateways/cecabank.rb +249 -0
  54. data/lib/active_merchant/billing/gateways/cenpos.rb +328 -0
  55. data/lib/active_merchant/billing/gateways/checkout.rb +212 -0
  56. data/lib/active_merchant/billing/gateways/checkout_v2.rb +587 -0
  57. data/lib/active_merchant/billing/gateways/citrus_pay.rb +21 -0
  58. data/lib/active_merchant/billing/gateways/clearhaus.rb +219 -0
  59. data/lib/active_merchant/billing/gateways/commerce_hub.rb +366 -0
  60. data/lib/active_merchant/billing/gateways/commercegate.rb +142 -0
  61. data/lib/active_merchant/billing/gateways/conekta.rb +230 -0
  62. data/lib/active_merchant/billing/gateways/creditcall.rb +272 -0
  63. data/lib/active_merchant/billing/gateways/credorax.rb +526 -0
  64. data/lib/active_merchant/billing/gateways/ct_payment.rb +269 -0
  65. data/lib/active_merchant/billing/gateways/culqi.rb +279 -0
  66. data/lib/active_merchant/billing/gateways/cyber_source/cyber_source_common.rb +36 -0
  67. data/lib/active_merchant/billing/gateways/cyber_source.rb +1148 -0
  68. data/lib/active_merchant/billing/gateways/cyber_source_rest.rb +454 -0
  69. data/lib/active_merchant/billing/gateways/d_local.rb +343 -0
  70. data/lib/active_merchant/billing/gateways/data_cash.rb +302 -0
  71. data/lib/active_merchant/billing/gateways/decidir.rb +358 -0
  72. data/lib/active_merchant/billing/gateways/decidir_plus.rb +344 -0
  73. data/lib/active_merchant/billing/gateways/dibs.rb +199 -0
  74. data/lib/active_merchant/billing/gateways/digitzs.rb +295 -0
  75. data/lib/active_merchant/billing/gateways/ebanx.rb +346 -0
  76. data/lib/active_merchant/billing/gateways/efsnet.rb +215 -0
  77. data/lib/active_merchant/billing/gateways/elavon.rb +475 -0
  78. data/lib/active_merchant/billing/gateways/element.rb +406 -0
  79. data/lib/active_merchant/billing/gateways/epay.rb +296 -0
  80. data/lib/active_merchant/billing/gateways/evo_ca.rb +307 -0
  81. data/lib/active_merchant/billing/gateways/eway.rb +226 -0
  82. data/lib/active_merchant/billing/gateways/eway_managed.rb +289 -0
  83. data/lib/active_merchant/billing/gateways/eway_rapid.rb +578 -0
  84. data/lib/active_merchant/billing/gateways/exact.rb +219 -0
  85. data/lib/active_merchant/billing/gateways/ezic.rb +195 -0
  86. data/lib/active_merchant/billing/gateways/fat_zebra.rb +223 -0
  87. data/lib/active_merchant/billing/gateways/federated_canada.rb +158 -0
  88. data/lib/active_merchant/billing/gateways/finansbank.rb +22 -0
  89. data/lib/active_merchant/billing/gateways/first_giving.rb +143 -0
  90. data/lib/active_merchant/billing/gateways/first_pay.rb +182 -0
  91. data/lib/active_merchant/billing/gateways/firstdata_e4.rb +452 -0
  92. data/lib/active_merchant/billing/gateways/firstdata_e4_v27.rb +505 -0
  93. data/lib/active_merchant/billing/gateways/flo2cash.rb +215 -0
  94. data/lib/active_merchant/billing/gateways/flo2cash_simple.rb +20 -0
  95. data/lib/active_merchant/billing/gateways/fluidpay.rb +275 -0
  96. data/lib/active_merchant/billing/gateways/forte.rb +286 -0
  97. data/lib/active_merchant/billing/gateways/garanti.rb +256 -0
  98. data/lib/active_merchant/billing/gateways/global_collect.rb +580 -0
  99. data/lib/active_merchant/billing/gateways/global_transport.rb +193 -0
  100. data/lib/active_merchant/billing/gateways/hdfc.rb +205 -0
  101. data/lib/active_merchant/billing/gateways/hps.rb +472 -0
  102. data/lib/active_merchant/billing/gateways/iats_payments.rb +312 -0
  103. data/lib/active_merchant/billing/gateways/in_context_paypal_express.rb +15 -0
  104. data/lib/active_merchant/billing/gateways/inspire.rb +213 -0
  105. data/lib/active_merchant/billing/gateways/instapay.rb +159 -0
  106. data/lib/active_merchant/billing/gateways/ipg.rb +420 -0
  107. data/lib/active_merchant/billing/gateways/ipp.rb +176 -0
  108. data/lib/active_merchant/billing/gateways/iridium.rb +467 -0
  109. data/lib/active_merchant/billing/gateways/itransact.rb +448 -0
  110. data/lib/active_merchant/billing/gateways/iveri.rb +290 -0
  111. data/lib/active_merchant/billing/gateways/ixopay.rb +320 -0
  112. data/lib/active_merchant/billing/gateways/jetpay.rb +395 -0
  113. data/lib/active_merchant/billing/gateways/jetpay_v2.rb +432 -0
  114. data/lib/active_merchant/billing/gateways/klarna.rb +317 -0
  115. data/lib/active_merchant/billing/gateways/komoju.rb +115 -0
  116. data/lib/active_merchant/billing/gateways/kushki.rb +297 -0
  117. data/lib/active_merchant/billing/gateways/latitude19.rb +412 -0
  118. data/lib/active_merchant/billing/gateways/linkpoint.rb +448 -0
  119. data/lib/active_merchant/billing/gateways/litle.rb +643 -0
  120. data/lib/active_merchant/billing/gateways/mastercard.rb +286 -0
  121. data/lib/active_merchant/billing/gateways/maxipago.rb +220 -0
  122. data/lib/active_merchant/billing/gateways/mercado_pago.rb +348 -0
  123. data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +228 -0
  124. data/lib/active_merchant/billing/gateways/merchant_one.rb +110 -0
  125. data/lib/active_merchant/billing/gateways/merchant_partners.rb +245 -0
  126. data/lib/active_merchant/billing/gateways/merchant_ware.rb +313 -0
  127. data/lib/active_merchant/billing/gateways/merchant_ware_version_four.rb +284 -0
  128. data/lib/active_merchant/billing/gateways/merchant_warrior.rb +248 -0
  129. data/lib/active_merchant/billing/gateways/mercury.rb +352 -0
  130. data/lib/active_merchant/billing/gateways/metrics_global.rb +293 -0
  131. data/lib/active_merchant/billing/gateways/micropayment.rb +182 -0
  132. data/lib/active_merchant/billing/gateways/migs/migs_codes.rb +100 -0
  133. data/lib/active_merchant/billing/gateways/migs.rb +329 -0
  134. data/lib/active_merchant/billing/gateways/mit.rb +260 -0
  135. data/lib/active_merchant/billing/gateways/modern_payments.rb +37 -0
  136. data/lib/active_merchant/billing/gateways/modern_payments_cim.rb +215 -0
  137. data/lib/active_merchant/billing/gateways/moka.rb +290 -0
  138. data/lib/active_merchant/billing/gateways/monei.rb +424 -0
  139. data/lib/active_merchant/billing/gateways/moneris.rb +488 -0
  140. data/lib/active_merchant/billing/gateways/money_movers.rb +150 -0
  141. data/lib/active_merchant/billing/gateways/mundipagg.rb +366 -0
  142. data/lib/active_merchant/billing/gateways/nab_transact.rb +299 -0
  143. data/lib/active_merchant/billing/gateways/ncr_secure_pay.rb +163 -0
  144. data/lib/active_merchant/billing/gateways/net_registry.rb +198 -0
  145. data/lib/active_merchant/billing/gateways/netaxept.rb +180 -0
  146. data/lib/active_merchant/billing/gateways/netbanx.rb +376 -0
  147. data/lib/active_merchant/billing/gateways/netbilling.rb +229 -0
  148. data/lib/active_merchant/billing/gateways/netpay.rb +223 -0
  149. data/lib/active_merchant/billing/gateways/network_merchants.rb +238 -0
  150. data/lib/active_merchant/billing/gateways/nmi.rb +396 -0
  151. data/lib/active_merchant/billing/gateways/ogone.rb +509 -0
  152. data/lib/active_merchant/billing/gateways/omise.rb +323 -0
  153. data/lib/active_merchant/billing/gateways/openpay.rb +246 -0
  154. data/lib/active_merchant/billing/gateways/opp.rb +394 -0
  155. data/lib/active_merchant/billing/gateways/optimal_payment.rb +331 -0
  156. data/lib/active_merchant/billing/gateways/orbital/orbital_soft_descriptors.rb +45 -0
  157. data/lib/active_merchant/billing/gateways/orbital.rb +1267 -0
  158. data/lib/active_merchant/billing/gateways/pac_net_raven.rb +206 -0
  159. data/lib/active_merchant/billing/gateways/pagarme.rb +239 -0
  160. data/lib/active_merchant/billing/gateways/pago_facil.rb +120 -0
  161. data/lib/active_merchant/billing/gateways/pay_arc.rb +392 -0
  162. data/lib/active_merchant/billing/gateways/pay_conex.rb +245 -0
  163. data/lib/active_merchant/billing/gateways/pay_gate_xml.rb +277 -0
  164. data/lib/active_merchant/billing/gateways/pay_hub.rb +213 -0
  165. data/lib/active_merchant/billing/gateways/pay_junction.rb +390 -0
  166. data/lib/active_merchant/billing/gateways/pay_junction_v2.rb +206 -0
  167. data/lib/active_merchant/billing/gateways/pay_secure.rb +110 -0
  168. data/lib/active_merchant/billing/gateways/pay_trace.rb +450 -0
  169. data/lib/active_merchant/billing/gateways/paybox_direct.rb +224 -0
  170. data/lib/active_merchant/billing/gateways/payeezy.rb +513 -0
  171. data/lib/active_merchant/billing/gateways/payex.rb +409 -0
  172. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +235 -0
  173. data/lib/active_merchant/billing/gateways/payflow/payflow_express_response.rb +42 -0
  174. data/lib/active_merchant/billing/gateways/payflow/payflow_response.rb +13 -0
  175. data/lib/active_merchant/billing/gateways/payflow.rb +473 -0
  176. data/lib/active_merchant/billing/gateways/payflow_express.rb +220 -0
  177. data/lib/active_merchant/billing/gateways/payflow_express_uk.rb +14 -0
  178. data/lib/active_merchant/billing/gateways/payflow_uk.rb +20 -0
  179. data/lib/active_merchant/billing/gateways/payment_express.rb +373 -0
  180. data/lib/active_merchant/billing/gateways/paymentez.rb +365 -0
  181. data/lib/active_merchant/billing/gateways/paymill.rb +369 -0
  182. data/lib/active_merchant/billing/gateways/paynetworx.rb +227 -0
  183. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +718 -0
  184. data/lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb +69 -0
  185. data/lib/active_merchant/billing/gateways/paypal/paypal_recurring_api.rb +262 -0
  186. data/lib/active_merchant/billing/gateways/paypal.rb +136 -0
  187. data/lib/active_merchant/billing/gateways/paypal_ca.rb +13 -0
  188. data/lib/active_merchant/billing/gateways/paypal_digital_goods.rb +44 -0
  189. data/lib/active_merchant/billing/gateways/paypal_express.rb +272 -0
  190. data/lib/active_merchant/billing/gateways/paypal_express_common.rb +30 -0
  191. data/lib/active_merchant/billing/gateways/paypal_standard.rb +281 -0
  192. data/lib/active_merchant/billing/gateways/paysafe.rb +420 -0
  193. data/lib/active_merchant/billing/gateways/payscout.rb +159 -0
  194. data/lib/active_merchant/billing/gateways/paystation.rb +204 -0
  195. data/lib/active_merchant/billing/gateways/payu_in.rb +249 -0
  196. data/lib/active_merchant/billing/gateways/payu_latam.rb +482 -0
  197. data/lib/active_merchant/billing/gateways/payway.rb +207 -0
  198. data/lib/active_merchant/billing/gateways/payway_dot_com.rb +253 -0
  199. data/lib/active_merchant/billing/gateways/pin.rb +273 -0
  200. data/lib/active_merchant/billing/gateways/pixxels.rb +263 -0
  201. data/lib/active_merchant/billing/gateways/plexo.rb +308 -0
  202. data/lib/active_merchant/billing/gateways/plugnpay.rb +283 -0
  203. data/lib/active_merchant/billing/gateways/priority.rb +392 -0
  204. data/lib/active_merchant/billing/gateways/pro_pay.rb +325 -0
  205. data/lib/active_merchant/billing/gateways/psigate.rb +227 -0
  206. data/lib/active_merchant/billing/gateways/psl_card.rb +295 -0
  207. data/lib/active_merchant/billing/gateways/qbms.rb +302 -0
  208. data/lib/active_merchant/billing/gateways/quantum.rb +274 -0
  209. data/lib/active_merchant/billing/gateways/quickbooks.rb +377 -0
  210. data/lib/active_merchant/billing/gateways/quickpay/quickpay_common.rb +184 -0
  211. data/lib/active_merchant/billing/gateways/quickpay/quickpay_v10.rb +297 -0
  212. data/lib/active_merchant/billing/gateways/quickpay/quickpay_v4to7.rb +226 -0
  213. data/lib/active_merchant/billing/gateways/quickpay.rb +24 -0
  214. data/lib/active_merchant/billing/gateways/qvalent.rb +305 -0
  215. data/lib/active_merchant/billing/gateways/rapyd.rb +319 -0
  216. data/lib/active_merchant/billing/gateways/reach.rb +277 -0
  217. data/lib/active_merchant/billing/gateways/realex.rb +400 -0
  218. data/lib/active_merchant/billing/gateways/redsys.rb +723 -0
  219. data/lib/active_merchant/billing/gateways/s5.rb +247 -0
  220. data/lib/active_merchant/billing/gateways/safe_charge.rb +298 -0
  221. data/lib/active_merchant/billing/gateways/sage.rb +446 -0
  222. data/lib/active_merchant/billing/gateways/sage_pay.rb +434 -0
  223. data/lib/active_merchant/billing/gateways/sallie_mae.rb +141 -0
  224. data/lib/active_merchant/billing/gateways/secure_net.rb +260 -0
  225. data/lib/active_merchant/billing/gateways/secure_pay.rb +191 -0
  226. data/lib/active_merchant/billing/gateways/secure_pay_au.rb +290 -0
  227. data/lib/active_merchant/billing/gateways/secure_pay_tech.rb +103 -0
  228. data/lib/active_merchant/billing/gateways/securion_pay.rb +305 -0
  229. data/lib/active_merchant/billing/gateways/shift4.rb +345 -0
  230. data/lib/active_merchant/billing/gateways/simetrik.rb +368 -0
  231. data/lib/active_merchant/billing/gateways/skip_jack.rb +450 -0
  232. data/lib/active_merchant/billing/gateways/smart_ps.rb +274 -0
  233. data/lib/active_merchant/billing/gateways/so_easy_pay.rb +194 -0
  234. data/lib/active_merchant/billing/gateways/spreedly_core.rb +312 -0
  235. data/lib/active_merchant/billing/gateways/stripe.rb +866 -0
  236. data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +602 -0
  237. data/lib/active_merchant/billing/gateways/swipe_checkout.rb +151 -0
  238. data/lib/active_merchant/billing/gateways/telr.rb +273 -0
  239. data/lib/active_merchant/billing/gateways/tns.rb +23 -0
  240. data/lib/active_merchant/billing/gateways/trans_first.rb +240 -0
  241. data/lib/active_merchant/billing/gateways/trans_first_transaction_express.rb +612 -0
  242. data/lib/active_merchant/billing/gateways/transact_pro.rb +222 -0
  243. data/lib/active_merchant/billing/gateways/transax.rb +21 -0
  244. data/lib/active_merchant/billing/gateways/transnational.rb +9 -0
  245. data/lib/active_merchant/billing/gateways/trexle.rb +221 -0
  246. data/lib/active_merchant/billing/gateways/trust_commerce.rb +500 -0
  247. data/lib/active_merchant/billing/gateways/usa_epay.rb +24 -0
  248. data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +1612 -0
  249. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +367 -0
  250. data/lib/active_merchant/billing/gateways/vanco.rb +303 -0
  251. data/lib/active_merchant/billing/gateways/verifi.rb +224 -0
  252. data/lib/active_merchant/billing/gateways/viaklix.rb +171 -0
  253. data/lib/active_merchant/billing/gateways/visanet_peru.rb +250 -0
  254. data/lib/active_merchant/billing/gateways/vpos.rb +223 -0
  255. data/lib/active_merchant/billing/gateways/webpay.rb +97 -0
  256. data/lib/active_merchant/billing/gateways/wepay.rb +235 -0
  257. data/lib/active_merchant/billing/gateways/wirecard.rb +430 -0
  258. data/lib/active_merchant/billing/gateways/wompi.rb +197 -0
  259. data/lib/active_merchant/billing/gateways/world_net.rb +345 -0
  260. data/lib/active_merchant/billing/gateways/worldpay.rb +1050 -0
  261. data/lib/active_merchant/billing/gateways/worldpay_online_payments.rb +208 -0
  262. data/lib/active_merchant/billing/gateways/worldpay_us.rb +221 -0
  263. data/lib/active_merchant/billing/gateways.rb +14 -0
  264. data/lib/active_merchant/billing/model.rb +30 -0
  265. data/lib/active_merchant/billing/network_tokenization_credit_card.rb +39 -0
  266. data/lib/active_merchant/billing/payment_token.rb +21 -0
  267. data/lib/active_merchant/billing/rails.rb +3 -0
  268. data/lib/active_merchant/billing/response.rb +120 -0
  269. data/lib/active_merchant/billing/three_d_secure_eci_mapper.rb +27 -0
  270. data/lib/active_merchant/billing.rb +16 -0
  271. data/lib/active_merchant/connection.rb +194 -0
  272. data/lib/active_merchant/country.rb +338 -0
  273. data/lib/active_merchant/empty.rb +20 -0
  274. data/lib/active_merchant/errors.rb +38 -0
  275. data/lib/active_merchant/net_http_ssl_connection.rb +11 -0
  276. data/lib/active_merchant/network_connection_retries.rb +78 -0
  277. data/lib/active_merchant/post_data.rb +26 -0
  278. data/lib/active_merchant/posts_data.rb +92 -0
  279. data/lib/active_merchant/version.rb +3 -0
  280. data/lib/active_merchant.rb +63 -0
  281. data/lib/activemerchant.rb +1 -0
  282. data/lib/certs/cacert.pem +3214 -0
  283. data/lib/support/gateway_support.rb +69 -0
  284. data/lib/support/outbound_hosts.rb +28 -0
  285. data/lib/support/ssl_verify.rb +88 -0
  286. data/lib/support/ssl_version.rb +86 -0
  287. metadata +506 -0
@@ -0,0 +1,1267 @@
1
+ require 'active_merchant/billing/gateways/orbital/orbital_soft_descriptors'
2
+ require 'rexml/document'
3
+
4
+ module ActiveMerchant #:nodoc:
5
+ module Billing #:nodoc:
6
+ # For more information on Orbital, visit the {integration center}[http://download.chasepaymentech.com]
7
+ #
8
+ # ==== Authentication Options
9
+ #
10
+ # The Orbital Gateway supports two methods of authenticating incoming requests:
11
+ # Source IP authentication and Connection Username/Password authentication
12
+ #
13
+ # In addition, these IP addresses/Connection Usernames must be affiliated with the Merchant IDs
14
+ # for which the client should be submitting transactions.
15
+ #
16
+ # This does allow Third Party Hosting service organizations presenting on behalf of other
17
+ # merchants to submit transactions. However, each time a new customer is added, the
18
+ # merchant or Third-Party hosting organization needs to ensure that the new Merchant IDs
19
+ # or Chain IDs are affiliated with the hosting companies IPs or Connection Usernames.
20
+ #
21
+ # If the merchant expects to have more than one merchant account with the Orbital
22
+ # Gateway, it should have its IP addresses/Connection Usernames affiliated at the Chain
23
+ # level hierarchy within the Orbital Gateway. Each time a new merchant ID is added, as
24
+ # long as it is placed within the same Chain, it will simply work. Otherwise, the additional
25
+ # MIDs will need to be affiliated with the merchant IPs or Connection Usernames respectively.
26
+ # For example, we generally affiliate all Salem accounts [BIN 000001] with
27
+ # their Company Number [formerly called MA #] number so all MIDs or Divisions under that
28
+ # Company will automatically be affiliated.
29
+
30
+ class OrbitalGateway < Gateway
31
+ include Empty
32
+
33
+ API_VERSION = '9.0'
34
+
35
+ POST_HEADERS = {
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'
42
+ }
43
+
44
+ SUCCESS = '0'
45
+ APPROVAL_SUCCESS = '1'
46
+
47
+ APPROVED = [
48
+ '00', # Approved
49
+ '08', # Approved authorization, honor with ID
50
+ '11', # Approved authorization, VIP approval
51
+ '24', # Validated
52
+ '26', # Pre-noted
53
+ '27', # No reason to decline
54
+ '28', # Received and stored
55
+ '29', # Provided authorization
56
+ '31', # Request received
57
+ '32', # BIN alert
58
+ '34', # Approved for partial
59
+ '91', # Approved low fraud
60
+ '92', # Approved medium fraud
61
+ '93', # Approved high fraud
62
+ '94', # Approved fraud service unavailable
63
+ 'E7', # Stored
64
+ 'PA', # Partial approval
65
+ 'P1' # ECP - AVS - Account Status Verification and/or AOA data is in a positive status.
66
+ ]
67
+
68
+ class_attribute :secondary_test_url, :secondary_live_url
69
+
70
+ self.test_url = 'https://orbitalvar1.chasepaymentech.com/authorize'
71
+ self.secondary_test_url = 'https://orbitalvar2.chasepaymentech.com/authorize'
72
+
73
+ self.live_url = 'https://orbital1.chasepaymentech.com/authorize'
74
+ self.secondary_live_url = 'https://orbital2.chasepaymentech.com/authorize'
75
+
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]
79
+
80
+ self.display_name = 'Orbital Paymentech'
81
+ self.homepage_url = 'http://chasepaymentech.com/'
82
+
83
+ self.money_format = :cents
84
+
85
+ AVS_SUPPORTED_COUNTRIES = %w[US CA UK GB]
86
+
87
+ CURRENCY_CODES = {
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
+ 'ZAR' => '710',
102
+ 'SEK' => '752',
103
+ 'CHF' => '756',
104
+ 'GBP' => '826',
105
+ 'USD' => '840',
106
+ 'EUR' => '978'
107
+ }
108
+
109
+ CURRENCY_EXPONENTS = {
110
+ 'AUD' => '2',
111
+ 'BRL' => '2',
112
+ 'CAD' => '2',
113
+ 'CLP' => '2',
114
+ 'CZK' => '2',
115
+ 'DKK' => '2',
116
+ 'HKD' => '2',
117
+ 'ICK' => '2',
118
+ 'JPY' => '0',
119
+ 'MXN' => '2',
120
+ 'NZD' => '2',
121
+ 'NOK' => '2',
122
+ 'SGD' => '2',
123
+ 'ZAR' => '2',
124
+ 'SEK' => '2',
125
+ 'CHF' => '2',
126
+ 'GBP' => '2',
127
+ 'USD' => '2',
128
+ 'EUR' => '2'
129
+ }
130
+
131
+ # INDUSTRY TYPES
132
+ ECOMMERCE_TRANSACTION = 'EC'
133
+ RECURRING_PAYMENT_TRANSACTION = 'RC'
134
+ MAIL_ORDER_TELEPHONE_ORDER_TRANSACTION = 'MO'
135
+ INTERACTIVE_VOICE_RESPONSE = 'IV'
136
+ # INTERACTIVE_VOICE_RESPONSE = 'IN'
137
+
138
+ # Auth Only No Capture
139
+ AUTH_ONLY = 'A'
140
+ # AC - Auth and Capture = 'AC'
141
+ AUTH_AND_CAPTURE = 'AC'
142
+ # F - Force Auth No Capture and no online authorization = 'F'
143
+ FORCE_AUTH_ONLY = 'F'
144
+ # FR - Force Auth No Capture and no online authorization = 'FR'
145
+ # FC - Force Auth and Capture no online authorization = 'FC'
146
+ FORCE_AUTH_AND_CAPTURE = 'FC'
147
+ # Refund and Capture no online authorization
148
+ REFUND = 'R'
149
+
150
+ # Tax Inds
151
+ TAX_NOT_PROVIDED = 0
152
+ TAX_INCLUDED = 1
153
+ NON_TAXABLE_TRANSACTION = 2
154
+
155
+ # Customer Profile Actions
156
+ CREATE = 'C'
157
+ RETRIEVE = 'R'
158
+ UPDATE = 'U'
159
+ DELETE = 'D'
160
+
161
+ RECURRING = 'R'
162
+ DEFERRED = 'D'
163
+
164
+ # Status
165
+ # Profile Status Flag
166
+ # This field is used to set the status of a Customer Profile.
167
+ ACTIVE = 'A'
168
+ INACTIVE = 'I'
169
+ MANUAL_SUSPEND = 'MS'
170
+
171
+ # CustomerProfileOrderOverrideInd
172
+ # Defines if any Order Data can be pre-populated from
173
+ # the Customer Reference Number (CustomerRefNum)
174
+ NO_MAPPING_TO_ORDER_DATA = 'NO'
175
+ USE_CRN_FOR_ORDER_ID = 'OI'
176
+ USE_CRN_FOR_COMMENTS = 'OD'
177
+ USE_CRN_FOR_ORDER_ID_AND_COMMENTS = 'OA'
178
+
179
+ # CustomerProfileFromOrderInd
180
+ # Method to use to Generate the Customer Profile Number
181
+ # When Customer Profile Action Type = Create, defines
182
+ # what the Customer Profile Number will be:
183
+ AUTO_GENERATE = 'A' # Auto-Generate the CustomerRefNum
184
+ USE_CUSTOMER_REF_NUM = 'S' # Use CustomerRefNum field
185
+ USE_ORDER_ID = 'O' # Use OrderID field
186
+ USE_COMMENTS = 'D' # Use Comments field
187
+
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
+ }
195
+
196
+ def initialize(options = {})
197
+ requires!(options, :merchant_id)
198
+ requires!(options, :login, :password) unless options[:ip_authentication]
199
+ super
200
+ @options[:merchant_id] = @options[:merchant_id].to_s
201
+ @use_secondary_url = false
202
+ end
203
+
204
+ # A – Authorization request
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])
214
+ end
215
+
216
+ def verify(credit_card, options = {})
217
+ amount = options[:verify_amount] ? options[:verify_amount].to_i : default_verify_amount(credit_card)
218
+ MultiResponse.run(:use_first_response) do |r|
219
+ r.process { authorize(amount, credit_card, options) }
220
+ r.process(:ignore_result) { void(r.authorization) } unless amount == 0
221
+ end
222
+ end
223
+
224
+ # AC – Authorization and Capture
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])
230
+ end
231
+
232
+ # MFC - Mark For Capture
233
+ def capture(money, authorization, options = {})
234
+ commit(build_mark_for_capture_xml(money, authorization, options), :capture, options[:retry_logic], options[:trace_number])
235
+ end
236
+
237
+ # R – Refund request
238
+ def refund(money, authorization, options = {})
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)
242
+ xml.tag! :CustomerRefNum, options[:customer_ref_num] if @options[:customer_profiles] && options[:profile_txn]
243
+ end
244
+
245
+ commit(order, :refund, options[:retry_logic], options[:trace_number])
246
+ end
247
+
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])
254
+ end
255
+
256
+ def void(authorization, options = {}, deprecated = {})
257
+ if !options.kind_of?(Hash)
258
+ ActiveMerchant.deprecated('Calling the void method with an amount parameter is deprecated and will be removed in a future version.')
259
+ return void(options, deprecated.merge(amount: authorization))
260
+ end
261
+
262
+ order = build_void_request_xml(authorization, options)
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)
274
+ end
275
+
276
+ # ==== Customer Profiles
277
+ # :customer_ref_num should be set unless you're happy with Orbital providing one
278
+ #
279
+ # :customer_profile_order_override_ind can be set to map
280
+ # the CustomerRefNum to OrderID or Comments. Defaults to 'NO' - no mapping
281
+ #
282
+ # 'NO' - No mapping to order data
283
+ # 'OI' - Use <CustomerRefNum> for <OrderID>
284
+ # 'OD' - Use <CustomerRefNum> for <Comments>
285
+ # 'OA' - Use <CustomerRefNum> for <OrderID> and <Comments>
286
+ #
287
+ # :order_default_description can be set optionally. 64 char max.
288
+ #
289
+ # :order_default_amount can be set optionally. integer as cents.
290
+ #
291
+ # :status defaults to Active
292
+ #
293
+ # 'A' - Active
294
+ # 'I' - Inactive
295
+ # 'MS' - Manual Suspend
296
+
297
+ def add_customer_profile(credit_card, options = {})
298
+ options[:customer_profile_action] = CREATE
299
+ order = build_customer_request_xml(credit_card, options)
300
+ commit(order, :add_customer_profile)
301
+ end
302
+
303
+ def update_customer_profile(credit_card, options = {})
304
+ options[:customer_profile_action] = UPDATE
305
+ order = build_customer_request_xml(credit_card, options)
306
+ commit(order, :update_customer_profile)
307
+ end
308
+
309
+ def retrieve_customer_profile(customer_ref_num)
310
+ options = { customer_profile_action: RETRIEVE, customer_ref_num: customer_ref_num }
311
+ order = build_customer_request_xml(nil, options)
312
+ commit(order, :retrieve_customer_profile)
313
+ end
314
+
315
+ def delete_customer_profile(customer_ref_num)
316
+ options = { customer_profile_action: DELETE, customer_ref_num: customer_ref_num }
317
+ order = build_customer_request_xml(nil, options)
318
+ commit(order, :delete_customer_profile)
319
+ end
320
+
321
+ def supports_network_tokenization?
322
+ true
323
+ end
324
+
325
+ def supports_scrubbing?
326
+ true
327
+ end
328
+
329
+ def scrub(transcript)
330
+ transcript.
331
+ gsub(%r((<OrbitalConnectionUsername>).+(</OrbitalConnectionUsername>)), '\1[FILTERED]\2').
332
+ gsub(%r((<OrbitalConnectionPassword>).+(</OrbitalConnectionPassword>)), '\1[FILTERED]\2').
333
+ gsub(%r((<AccountNum>).+(</AccountNum>)), '\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').
336
+ gsub(%r((<CardSecVal>).+(</CardSecVal>)), '\1[FILTERED]\2').
337
+ gsub(%r((<MerchantID>).+(</MerchantID>)), '\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')
343
+ end
344
+
345
+ private
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
+
383
+ def authorization_string(*args)
384
+ args.compact.join(';')
385
+ end
386
+
387
+ def split_authorization(authorization)
388
+ authorization.split(';')
389
+ end
390
+
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
404
+ end
405
+
406
+ def add_soft_descriptors_from_specialized_class(xml, soft_desc)
407
+ xml.tag! :SDMerchantName, soft_desc.merchant_name if soft_desc.merchant_name
408
+ xml.tag! :SDProductDescription, soft_desc.product_description if soft_desc.product_description
409
+ xml.tag! :SDMerchantCity, soft_desc.merchant_city if soft_desc.merchant_city
410
+ xml.tag! :SDMerchantPhone, soft_desc.merchant_phone if soft_desc.merchant_phone
411
+ xml.tag! :SDMerchantURL, soft_desc.merchant_url if soft_desc.merchant_url
412
+ xml.tag! :SDMerchantEmail, soft_desc.merchant_email if soft_desc.merchant_email
413
+ end
414
+
415
+ def add_soft_descriptors_from_hash(xml, soft_desc)
416
+ xml.tag! :SDMerchantName, soft_desc[:merchant_name] || nil
417
+ xml.tag! :SDProductDescription, soft_desc[:product_description] || nil
418
+ xml.tag! :SDMerchantCity, soft_desc[:merchant_city] || nil
419
+ xml.tag! :SDMerchantPhone, soft_desc[:merchant_phone] || nil
420
+ xml.tag! :SDMerchantURL, soft_desc[:merchant_url] || nil
421
+ xml.tag! :SDMerchantEmail, soft_desc[:merchant_email] || nil
422
+ end
423
+
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]
428
+ end
429
+ end
430
+
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]
437
+ end
438
+ end
439
+
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]
446
+ end
447
+ end
448
+
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
460
+
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
470
+
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
487
+ end
488
+ end
489
+
490
+ #=====ADDRESS FIELDS=====
491
+
492
+ def add_address(xml, payment_source, options)
493
+ return unless (address = get_address(options))
494
+
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)
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])
522
+ end
523
+
524
+ # For Profile requests
525
+ def add_customer_address(xml, options)
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
537
+
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]
543
+ end
544
+ end
545
+
546
+ def avs_supported?(address)
547
+ AVS_SUPPORTED_COUNTRIES.include?(address.to_s)
548
+ end
549
+
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?
587
+
588
+ # If you are trying to collect a Card Verification Number
589
+ # (CardSecVal) for a Visa or Discover transaction, pass one of these values:
590
+ # 1 Value is Present
591
+ # 2 Value on card but illegible
592
+ # 9 Cardholder states data not available
593
+ # If the transaction is not a Visa or Discover transaction:
594
+ # Null-fill this attribute OR
595
+ # Do not submit the attribute at all.
596
+ # - http://download.chasepaymentech.com/docs/orbital/orbital_gateway_xml_specification.pdf
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]
612
+ end
613
+
614
+ xml.tag! :BankAccountType, bank_account_type if bank_account_type
615
+ end
616
+
617
+ def add_card_indicators(xml, options)
618
+ xml.tag! :CardIndicators, options[:card_indicators] if options[:card_indicators]
619
+ end
620
+
621
+ def currency_code(currency)
622
+ CURRENCY_CODES[(currency || self.default_currency)].to_s
623
+ end
624
+
625
+ def currency_exponents(currency)
626
+ CURRENCY_EXPONENTS[(currency || self.default_currency)].to_s
627
+ end
628
+
629
+ def expiry_date(credit_card)
630
+ "#{format(credit_card.month, :two_digits)}#{format(credit_card.year, :two_digits)}"
631
+ end
632
+
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'
645
+
646
+ xml.tag!(:CAVV, three_d_secure[:cavv])
647
+ end
648
+
649
+ def add_aav(xml, credit_card, three_d_secure)
650
+ return unless three_d_secure && credit_card.brand == 'master'
651
+
652
+ xml.tag!(:AAV, three_d_secure[:cavv])
653
+ end
654
+
655
+ def add_aevv(xml, credit_card, three_d_secure)
656
+ return unless three_d_secure && credit_card.brand == 'american_express'
657
+
658
+ xml.tag!(:AEVV, three_d_secure[:cavv])
659
+ end
660
+
661
+ def add_xid(xml, credit_card, three_d_secure)
662
+ return unless three_d_secure && credit_card.brand == 'visa'
663
+
664
+ xml.tag!(:XID, three_d_secure[:xid]) if three_d_secure[:xid]
665
+ end
666
+
667
+ def add_pymt_brand_program_code(xml, credit_card, three_d_secure)
668
+ return unless three_d_secure && credit_card.brand == 'american_express'
669
+
670
+ xml.tag!(:PymtBrandProgramCode, 'ASK')
671
+ end
672
+
673
+ def mastercard?(payment_source)
674
+ payment_source.is_a?(CreditCard) && payment_source.brand == 'master'
675
+ end
676
+
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)
683
+ end
684
+
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'
688
+
689
+ xml.tag!(:SCAMerchantInitiatedTransaction, parameters[:sca_merchant_initiated])
690
+ end
691
+
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]
709
+ end
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
+
719
+ def add_stored_credentials(xml, parameters)
720
+ return unless parameters[:mit_stored_credential_ind] == 'Y' || parameters[:stored_credential] && !parameters[:stored_credential].values.all?(&:nil?)
721
+
722
+ if msg_type = get_msg_type(parameters)
723
+ xml.tag! :MITMsgType, msg_type
724
+ end
725
+ xml.tag! :MITStoredCredentialInd, 'Y'
726
+ if parameters[:mit_submitted_transaction_id]
727
+ xml.tag! :MITSubmittedTransactionID, parameters[:mit_submitted_transaction_id]
728
+ elsif parameters.dig(:stored_credential, :network_transaction_id) && parameters.dig(:stored_credential, :initiator) == 'merchant'
729
+ xml.tag! :MITSubmittedTransactionID, parameters[:stored_credential][:network_transaction_id]
730
+ end
731
+ end
732
+
733
+ def get_msg_type(parameters)
734
+ return parameters[:mit_msg_type] if parameters[:mit_msg_type]
735
+ return 'CSTO' if parameters[:stored_credential][:initial_transaction]
736
+ return unless parameters[:stored_credential][:initiator] && parameters[:stored_credential][:reason_type]
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
749
+
750
+ "#{initiator}#{reason}"
751
+ end
752
+
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
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)
833
+ end
834
+
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')
838
+ end
839
+
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)
853
+ end
854
+ end
855
+
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)
872
+ headers = POST_HEADERS.merge('Content-length' => order.size.to_s)
873
+ if (@options[:retry_logic] || retry_logic) && trace_number
874
+ headers['Trace-number'] = trace_number.to_s
875
+ headers['Merchant-Id'] = @options[:merchant_id]
876
+ end
877
+ request = ->(url) { parse(ssl_post(url, order, headers)) }
878
+
879
+ # Failover URL will be attempted in the event of a connection error
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
888
+
889
+ Response.new(success?(response, message_type), message_from(response), response,
890
+ {
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
+ })
896
+ end
897
+
898
+ def remote_url(url = :primary)
899
+ if url == :primary
900
+ (self.test? ? self.test_url : self.live_url)
901
+ else
902
+ (self.test? ? self.secondary_test_url : self.secondary_live_url)
903
+ end
904
+ end
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
+
928
+ def success?(response, message_type)
929
+ if %i[void].include?(message_type)
930
+ response[:proc_status] == SUCCESS
931
+ elsif %i[refund].include?(message_type)
932
+ response[:proc_status] == SUCCESS && response[:approval_status] == APPROVAL_SUCCESS
933
+ elsif response[:customer_profile_action]
934
+ response[:profile_proc_status] == SUCCESS
935
+ else
936
+ response[:proc_status] == SUCCESS &&
937
+ APPROVED.include?(response[:resp_code])
938
+ end
939
+ end
940
+
941
+ def message_from(response)
942
+ response[:resp_msg] || response[:status_msg] || response[:customer_profile_message]
943
+ end
944
+
945
+ def ip_authentication?
946
+ @options[:ip_authentication] == true
947
+ end
948
+
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 = {})
963
+ requires!(parameters, :order_id)
964
+ @use_secondary_url = parameters[:use_secondary_url] if parameters[:use_secondary_url]
965
+ xml = xml_envelope
966
+ xml.tag! :Request do
967
+ xml.tag! :NewOrder do
968
+ add_xml_credentials(xml)
969
+ xml.tag! :IndustryType, parameters[:industry_type] || ECOMMERCE_TRANSACTION
970
+ xml.tag! :MessageType, action
971
+ add_bin_merchant_and_terminal(xml, parameters)
972
+
973
+ yield xml if block_given?
974
+
975
+ three_d_secure = parameters[:three_d_secure]
976
+
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)
980
+
981
+ xml.tag! :OrderID, format_order_id(parameters[:order_id])
982
+ xml.tag! :Amount, amount(money)
983
+ xml.tag! :Comments, parameters[:comments] if parameters[:comments]
984
+
985
+ add_level2_tax(xml, parameters)
986
+ add_level2_advice_addendum(xml, parameters)
987
+
988
+ add_aav(xml, payment_source, three_d_secure)
989
+ # CustomerAni, AVSPhoneType and AVSDestPhoneType could be added here.
990
+
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)
996
+
997
+ xml.tag! :ECPSameDayInd, parameters[:same_day] if parameters[:same_day] && payment_source.is_a?(Check)
998
+
999
+ set_recurring_ind(xml, parameters)
1000
+
1001
+ # Append Transaction Reference Number at the end for Refund transactions
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)
1010
+ add_stored_credentials(xml, parameters)
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)
1013
+ end
1014
+ end
1015
+ xml.target!
1016
+ end
1017
+
1018
+ def build_mark_for_capture_xml(money, authorization, parameters = {})
1019
+ tx_ref_num, order_id = split_authorization(authorization)
1020
+ xml = xml_envelope
1021
+ xml.tag! :Request do
1022
+ xml.tag! :MarkForCapture do
1023
+ add_xml_credentials(xml)
1024
+ xml.tag! :OrderID, format_order_id(order_id)
1025
+ xml.tag! :Amount, amount(money)
1026
+ add_level2_tax(xml, parameters)
1027
+ add_bin_merchant_and_terminal(xml, parameters)
1028
+ xml.tag! :TxRefNum, tx_ref_num
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]
1034
+ end
1035
+ end
1036
+ xml.target!
1037
+ end
1038
+
1039
+ def build_void_request_xml(authorization, parameters = {})
1040
+ tx_ref_num, order_id = split_authorization(authorization)
1041
+ xml = xml_envelope
1042
+ xml.tag! :Request do
1043
+ xml.tag! :Reversal do
1044
+ add_xml_credentials(xml)
1045
+ xml.tag! :TxRefNum, tx_ref_num
1046
+ xml.tag! :TxRefIdx, parameters[:transaction_index]
1047
+ xml.tag! :AdjustedAmt, parameters[:amount] # setting adjusted amount to nil will void entire amount
1048
+ xml.tag! :OrderID, format_order_id(order_id || parameters[:order_id])
1049
+ add_bin_merchant_and_terminal(xml, parameters)
1050
+ xml.tag! :ReversalRetryNumber, parameters[:reversal_retry_number] if parameters[:reversal_retry_number]
1051
+ xml.tag! :OnlineReversalInd, parameters[:online_reversal_ind] if parameters[:online_reversal_ind]
1052
+ end
1053
+ end
1054
+ xml.target!
1055
+ end
1056
+
1057
+ def xml_envelope
1058
+ xml = Builder::XmlMarkup.new(indent: 2)
1059
+ xml.instruct!(:xml, version: '1.0', encoding: 'UTF-8')
1060
+ xml
1061
+ end
1062
+
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]')
1067
+ end
1068
+
1069
+ # The valid characters include:
1070
+ #
1071
+ # 1. all letters and digits
1072
+ # 2. - , $ @ & and a space character, though the space character cannot be the leading character
1073
+ # 3. PINless Debit transactions can only use uppercase and lowercase alpha (A-Z, a-z) and numeric (0-9)
1074
+ def format_order_id(order_id)
1075
+ illegal_characters = /[^,$@&\- \w]/
1076
+ order_id = order_id.to_s.tr('.', '-')
1077
+ order_id.gsub!(illegal_characters, '')
1078
+ order_id.lstrip!
1079
+ order_id[0...22]
1080
+ end
1081
+
1082
+ # Address-related fields cannot contain % | ^ \ /
1083
+ # Returns the value with these characters removed, or nil
1084
+ def format_address_field(value)
1085
+ value.gsub(/[%\|\^\\\/]/, '') if value.respond_to?(:gsub)
1086
+ end
1087
+
1088
+ # Field lengths should be limited by byte count instead of character count
1089
+ # Returns the truncated value or nil
1090
+ def byte_limit(value, byte_length)
1091
+ limited_value = ''
1092
+
1093
+ value.to_s.each_char do |c|
1094
+ break if (limited_value.bytesize + c.bytesize) > byte_length
1095
+
1096
+ limited_value << c
1097
+ end
1098
+
1099
+ limited_value
1100
+ end
1101
+
1102
+ def build_customer_request_xml(credit_card, options = {})
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.'
1104
+ xml = xml_envelope
1105
+ xml.tag! :Request do
1106
+ xml.tag! :Profile do
1107
+ xml.tag! :OrbitalConnectionUsername, @options[:login] unless ip_authentication?
1108
+ xml.tag! :OrbitalConnectionPassword, @options[:password] unless ip_authentication?
1109
+ xml.tag! :CustomerBin, bin
1110
+ xml.tag! :CustomerMerchantID, @options[:merchant_id]
1111
+ xml.tag! :CustomerName, credit_card.name if credit_card
1112
+ xml.tag! :CustomerRefNum, options[:customer_ref_num] if options[:customer_ref_num]
1113
+
1114
+ add_customer_address(xml, options)
1115
+
1116
+ xml.tag! :CustomerProfileAction, options[:customer_profile_action] # C, R, U, D
1117
+ # NO No mapping to order data
1118
+ # OI Use <CustomerRefNum> for <OrderID>
1119
+ # OD Use <CustomerReferNum> for <Comments>
1120
+ # OA Use <CustomerRefNum> for <OrderID> and <Comments>
1121
+ xml.tag! :CustomerProfileOrderOverrideInd, options[:customer_profile_order_override_ind] || NO_MAPPING_TO_ORDER_DATA
1122
+
1123
+ if options[:customer_profile_action] == CREATE
1124
+ # A Auto-Generate the CustomerRefNum
1125
+ # S Use CustomerRefNum field
1126
+ # O Use OrderID field
1127
+ # D Use Comments field
1128
+ xml.tag! :CustomerProfileFromOrderInd, (options[:customer_ref_num] ? USE_CUSTOMER_REF_NUM : AUTO_GENERATE)
1129
+ end
1130
+
1131
+ xml.tag! :OrderDefaultDescription, options[:order_default_description][0..63] if options[:order_default_description]
1132
+ xml.tag! :OrderDefaultAmount, options[:order_default_amount] if options[:order_default_amount]
1133
+
1134
+ if [CREATE, UPDATE].include? options[:customer_profile_action]
1135
+ xml.tag! :CustomerAccountType, 'CC' # Only credit card supported
1136
+ xml.tag! :Status, options[:status] || ACTIVE # Active
1137
+ end
1138
+
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
1141
+
1142
+ # This has to come after CCExpireDate.
1143
+ add_managed_billing(xml, options)
1144
+ end
1145
+ end
1146
+ xml.target!
1147
+ end
1148
+
1149
+ # Unfortunately, Orbital uses their own special codes for AVS responses
1150
+ # that are different than the standard codes defined in
1151
+ # <tt>ActiveMerchant::Billing::AVSResult</tt>.
1152
+ #
1153
+ # This class encapsulates the response codes shown on page 240 of their spec:
1154
+ # http://download.chasepaymentech.com/docs/orbital/orbital_gateway_xml_specification.pdf
1155
+ #
1156
+ class AVSResult < ActiveMerchant::Billing::AVSResult
1157
+ CODES = {
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'
1199
+ }
1200
+
1201
+ # Map vendor's AVS result code to a postal match code
1202
+ ORBITAL_POSTAL_MATCH_CODE = {
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)
1207
+ }.inject({}) do |map, (type, codes)|
1208
+ codes.each { |code| map[code] = type }
1209
+ map
1210
+ end
1211
+
1212
+ # Map vendor's AVS result code to a street match code
1213
+ ORBITAL_STREET_MATCH_CODE = {
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)
1218
+ }.inject({}) do |map, (type, codes)|
1219
+ codes.each { |code| map[code] = type }
1220
+ map
1221
+ end
1222
+
1223
+ def self.messages
1224
+ CODES
1225
+ end
1226
+
1227
+ def initialize(code)
1228
+ @code = (code.blank? ? nil : code.to_s.strip.upcase)
1229
+ if @code
1230
+ @message = CODES[@code]
1231
+ @postal_match = ORBITAL_POSTAL_MATCH_CODE[@code]
1232
+ @street_match = ORBITAL_STREET_MATCH_CODE[@code]
1233
+ end
1234
+ end
1235
+ end
1236
+
1237
+ # Unfortunately, Orbital uses their own special codes for CVV responses
1238
+ # that are different than the standard codes defined in
1239
+ # <tt>ActiveMerchant::Billing::CVVResult</tt>.
1240
+ #
1241
+ # This class encapsulates the response codes shown on page 255 of their spec:
1242
+ # http://download.chasepaymentech.com/docs/orbital/orbital_gateway_xml_specification.pdf
1243
+ #
1244
+ class CVVResult < ActiveMerchant::Billing::CVVResult
1245
+ MESSAGES = {
1246
+ 'M' => 'Match',
1247
+ 'N' => 'No match',
1248
+ 'P' => 'Not processed',
1249
+ 'S' => 'Should have been present',
1250
+ 'U' => 'Unsupported by issuer/Issuer unable to process request',
1251
+ 'I' => 'Invalid',
1252
+ 'Y' => 'Invalid',
1253
+ '' => 'Not applicable'
1254
+ }
1255
+
1256
+ def self.messages
1257
+ MESSAGES
1258
+ end
1259
+
1260
+ def initialize(code)
1261
+ @code = code.blank? ? '' : code.upcase
1262
+ @message = MESSAGES[@code]
1263
+ end
1264
+ end
1265
+ end
1266
+ end
1267
+ end