swiss-crm-activemerchant 1.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 +252 -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 +242 -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 +228 -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 +354 -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 +121 -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,1050 @@
1
+ require 'nokogiri'
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+ class WorldpayGateway < Gateway
6
+ self.test_url = 'https://secure-test.worldpay.com/jsp/merchant/xml/paymentService.jsp'
7
+ self.live_url = 'https://secure.worldpay.com/jsp/merchant/xml/paymentService.jsp'
8
+
9
+ self.default_currency = 'GBP'
10
+ self.money_format = :cents
11
+ self.supported_countries = %w(AD AE AG AI AL AM AO AR AS AT AU AW AX AZ BA BB BD BE BF BG BH BI BJ BM BN BO BR BS BT BW
12
+ BY BZ CA CC CF CH CK CL CM CN CO CR CV CX CY CZ DE DJ DK DO DZ EC EE EG EH ES ET FI FJ FK
13
+ FM FO FR GA GB GD GE GF GG GH GI GL GM GN GP GQ GR GT GU GW GY HK HM HN HR HT HU ID IE IL
14
+ IM IN IO IS IT JE JM JO JP KE KG KH KI KM KN KR KW KY KZ LA LC LI LK LS LT LU LV MA MC MD
15
+ ME MG MH MK ML MN MO MP MQ MR MS MT MU MV MW MX MY MZ NA NC NE NF NG NI NL NO NP NR NU NZ
16
+ OM PA PE PF PH PK PL PN PR PT PW PY QA RE RO RS RU RW SA SB SC SE SG SI SK SL SM SN ST SV
17
+ SZ TC TD TF TG TH TJ TK TM TO TR TT TV TW TZ UA UG US UY UZ VA VC VE VI VN VU WF WS YE YT
18
+ ZA ZM)
19
+ self.supported_cardtypes = %i[visa master american_express discover jcb maestro elo naranja cabal unionpay]
20
+ self.currencies_without_fractions = %w(HUF IDR JPY KRW BEF XOF XAF XPF GRD GNF ITL LUF MGA MGF PYG PTE RWF ESP TRL VND KMF)
21
+ self.currencies_with_three_decimal_places = %w(BHD KWD OMR TND LYD JOD IQD)
22
+ self.homepage_url = 'http://www.worldpay.com/'
23
+ self.display_name = 'Worldpay Global'
24
+
25
+ NETWORK_TOKEN_TYPE = {
26
+ apple_pay: 'APPLEPAY',
27
+ google_pay: 'GOOGLEPAY',
28
+ network_token: 'NETWORKTOKEN'
29
+ }
30
+
31
+ CARD_CODES = {
32
+ 'visa' => 'VISA-SSL',
33
+ 'master' => 'ECMC-SSL',
34
+ 'discover' => 'DISCOVER-SSL',
35
+ 'american_express' => 'AMEX-SSL',
36
+ 'jcb' => 'JCB-SSL',
37
+ 'maestro' => 'MAESTRO-SSL',
38
+ 'diners_club' => 'DINERS-SSL',
39
+ 'elo' => 'ELO-SSL',
40
+ 'naranja' => 'NARANJA-SSL',
41
+ 'cabal' => 'CABAL-SSL',
42
+ 'unionpay' => 'CHINAUNIONPAY-SSL',
43
+ 'unknown' => 'CARD-SSL'
44
+ }
45
+
46
+ AVS_CODE_MAP = {
47
+ 'A' => 'M', # Match
48
+ 'B' => 'P', # Postcode matches, address not verified
49
+ 'C' => 'Z', # Postcode matches, address does not match
50
+ 'D' => 'B', # Address matched; postcode not checked
51
+ 'E' => 'I', # Address and postal code not checked
52
+ 'F' => 'A', # Address matches, postcode does not match
53
+ 'G' => 'C', # Address does not match, postcode not checked
54
+ 'H' => 'I', # Address and postcode not provided
55
+ 'I' => 'C', # Address not checked postcode does not match
56
+ 'J' => 'C', # Address and postcode does not match
57
+ }
58
+
59
+ CVC_CODE_MAP = {
60
+ 'A' => 'M', # CVV matches
61
+ 'B' => 'P', # Not provided
62
+ 'C' => 'P', # Not checked
63
+ 'D' => 'N', # Does not match
64
+ }
65
+
66
+ def initialize(options = {})
67
+ requires!(options, :login, :password)
68
+ super
69
+ end
70
+
71
+ def purchase(money, payment_method, options = {})
72
+ MultiResponse.run do |r|
73
+ r.process { authorize(money, payment_method, options) }
74
+ r.process { capture(money, r.authorization, options.merge(authorization_validated: true)) } unless options[:skip_capture]
75
+ end
76
+ end
77
+
78
+ def authorize(money, payment_method, options = {})
79
+ requires!(options, :order_id)
80
+ payment_details = payment_details(payment_method)
81
+ authorize_request(money, payment_method, payment_details.merge(options))
82
+ end
83
+
84
+ def capture(money, authorization, options = {})
85
+ authorization = order_id_from_authorization(authorization.to_s)
86
+ MultiResponse.run do |r|
87
+ r.process { inquire_request(authorization, options, 'AUTHORISED', 'CAPTURED') } unless options[:authorization_validated]
88
+ if r.params
89
+ authorization_currency = r.params['amount_currency_code']
90
+ options = options.merge(currency: authorization_currency) if authorization_currency.present?
91
+ end
92
+ r.process { capture_request(money, authorization, options) }
93
+ end
94
+ end
95
+
96
+ def void(authorization, options = {})
97
+ authorization = order_id_from_authorization(authorization.to_s)
98
+ MultiResponse.run do |r|
99
+ r.process { inquire_request(authorization, options, 'AUTHORISED') } unless options[:authorization_validated]
100
+ r.process { cancel_request(authorization, options) }
101
+ end
102
+ end
103
+
104
+ def refund(money, authorization, options = {})
105
+ authorization = order_id_from_authorization(authorization.to_s)
106
+ success_criteria = %w(CAPTURED SETTLED SETTLED_BY_MERCHANT SENT_FOR_REFUND)
107
+ success_criteria.push('AUTHORIZED') if options[:cancel_or_refund]
108
+ response = MultiResponse.run do |r|
109
+ r.process { inquire_request(authorization, options, *success_criteria) } unless options[:authorization_validated]
110
+ r.process { refund_request(money, authorization, options) }
111
+ end
112
+
113
+ if !response.success? && options[:force_full_refund_if_unsettled] &&
114
+ response.params['last_event'] == 'AUTHORISED'
115
+ void(authorization, options)
116
+ else
117
+ response
118
+ end
119
+ end
120
+
121
+ # Credits only function on a Merchant ID/login/profile flagged for Payouts
122
+ # aka Credit Fund Transfers (CFT), whereas normal purchases, refunds,
123
+ # and other transactions should be performed on a normal eCom-flagged
124
+ # merchant ID.
125
+ def credit(money, payment_method, options = {})
126
+ payment_details = payment_details(payment_method)
127
+ if options[:fast_fund_credit]
128
+ fast_fund_credit_request(money, payment_method, payment_details.merge(credit: true, **options))
129
+ else
130
+ credit_request(money, payment_method, payment_details.merge(credit: true, **options))
131
+ end
132
+ end
133
+
134
+ def verify(payment_method, options = {})
135
+ amount = (eligible_for_0_auth?(payment_method, options) ? 0 : 100)
136
+ MultiResponse.run(:use_first_response) do |r|
137
+ r.process { authorize(amount, payment_method, options) }
138
+ r.process(:ignore_result) { void(r.authorization, options.merge(authorization_validated: true)) }
139
+ end
140
+ end
141
+
142
+ def store(credit_card, options = {})
143
+ requires!(options, :customer)
144
+ store_request(credit_card, options)
145
+ end
146
+
147
+ def inquire(authorization, options = {})
148
+ order_id = order_id_from_authorization(authorization.to_s) || options[:order_id]
149
+ commit('direct_inquiry', build_order_inquiry_request(order_id, options), :ok, options)
150
+ end
151
+
152
+ def supports_scrubbing
153
+ true
154
+ end
155
+
156
+ def supports_network_tokenization?
157
+ true
158
+ end
159
+
160
+ def scrub(transcript)
161
+ transcript.
162
+ gsub(%r((Authorization: Basic )\w+), '\1[FILTERED]').
163
+ gsub(%r((<cardNumber>)\d+(</cardNumber>)), '\1[FILTERED]\2').
164
+ gsub(%r((<cvc>)[^<]+(</cvc>)), '\1[FILTERED]\2').
165
+ gsub(%r((<tokenNumber>)\d+(</tokenNumber>)), '\1[FILTERED]\2').
166
+ gsub(%r((<cryptogram>)[^<]+(</cryptogram>)), '\1[FILTERED]\2')
167
+ end
168
+
169
+ private
170
+
171
+ def authorize_request(money, payment_method, options)
172
+ commit('authorize', build_authorization_request(money, payment_method, options), 'AUTHORISED', 'CAPTURED', options)
173
+ end
174
+
175
+ def capture_request(money, authorization, options)
176
+ commit('capture', build_capture_request(money, authorization, options), 'CAPTURED', :ok, options)
177
+ end
178
+
179
+ def cancel_request(authorization, options)
180
+ commit('cancel', build_void_request(authorization, options), :ok, options)
181
+ end
182
+
183
+ def inquire_request(authorization, options, *success_criteria)
184
+ commit('inquiry', build_order_inquiry_request(authorization, options), *success_criteria, options)
185
+ end
186
+
187
+ def refund_request(money, authorization, options)
188
+ commit('refund', build_refund_request(money, authorization, options), :ok, 'SENT_FOR_REFUND', options)
189
+ end
190
+
191
+ def credit_request(money, payment_method, options)
192
+ commit('credit', build_authorization_request(money, payment_method, options), :ok, 'SENT_FOR_REFUND', options)
193
+ end
194
+
195
+ def fast_fund_credit_request(money, payment_method, options)
196
+ commit('fast_credit', build_fast_fund_credit_request(money, payment_method, options), :ok, 'PUSH_APPROVED', options)
197
+ end
198
+
199
+ def store_request(credit_card, options)
200
+ commit('store', build_store_request(credit_card, options), options)
201
+ end
202
+
203
+ def build_request
204
+ xml = Builder::XmlMarkup.new indent: 2
205
+ xml.instruct! :xml, encoding: 'UTF-8'
206
+ xml.declare! :DOCTYPE, :paymentService, :PUBLIC, '-//WorldPay//DTD WorldPay PaymentService v1//EN', 'http://dtd.worldpay.com/paymentService_v1.dtd'
207
+ xml.paymentService 'version' => '1.4', 'merchantCode' => @options[:login] do
208
+ yield xml
209
+ end
210
+ xml.target!
211
+ end
212
+
213
+ def build_order_modify_request(authorization)
214
+ build_request do |xml|
215
+ xml.modify do
216
+ xml.orderModification 'orderCode' => authorization do
217
+ yield xml
218
+ end
219
+ end
220
+ end
221
+ end
222
+
223
+ def build_order_inquiry_request(authorization, options)
224
+ build_request do |xml|
225
+ xml.inquiry do
226
+ xml.orderInquiry 'orderCode' => authorization
227
+ end
228
+ end
229
+ end
230
+
231
+ def build_authorization_request(money, payment_method, options)
232
+ build_request do |xml|
233
+ xml.submit do
234
+ xml.order order_tag_attributes(options) do
235
+ xml.description(options[:description].blank? ? 'Purchase' : options[:description])
236
+ add_amount(xml, money, options)
237
+ add_order_content(xml, options)
238
+ add_payment_method(xml, money, payment_method, options)
239
+ add_shopper(xml, options)
240
+ add_statement_narrative(xml, options)
241
+ add_risk_data(xml, options[:risk_data]) if options[:risk_data]
242
+ add_sub_merchant_data(xml, options[:sub_merchant_data]) if options[:sub_merchant_data]
243
+ add_hcg_additional_data(xml, options) if options[:hcg_additional_data]
244
+ add_instalments_data(xml, options) if options[:instalments]
245
+ add_additional_data(xml, money, options) if options[:level_2_data] || options[:level_3_data]
246
+ add_moto_flag(xml, options) if options.dig(:metadata, :manual_entry)
247
+ add_additional_3ds_data(xml, options) if options[:execute_threed] && options[:three_ds_version] && options[:three_ds_version] =~ /^2/
248
+ add_3ds_exemption(xml, options) if options[:exemption_type]
249
+ end
250
+ end
251
+ end
252
+ end
253
+
254
+ def add_additional_data(xml, amount, options)
255
+ level_two_data = options[:level_2_data] || {}
256
+ level_three_data = options[:level_3_data] || {}
257
+ level_two_and_three_data = level_two_data.merge(level_three_data).symbolize_keys
258
+
259
+ xml.branchSpecificExtension do
260
+ xml.purchase do
261
+ add_level_two_and_three_data(xml, amount, level_two_and_three_data)
262
+ end
263
+ end
264
+ end
265
+
266
+ def add_level_two_and_three_data(xml, amount, data)
267
+ xml.invoiceReferenceNumber data[:invoice_reference_number] if data.include?(:invoice_reference_number)
268
+ xml.customerReference data[:customer_reference] if data.include?(:customer_reference)
269
+ xml.cardAcceptorTaxId data[:card_acceptor_tax_id] if data.include?(:card_acceptor_tax_id)
270
+
271
+ {
272
+ sales_tax: 'salesTax',
273
+ discount_amount: 'discountAmount',
274
+ shipping_amount: 'shippingAmount',
275
+ duty_amount: 'dutyAmount'
276
+ }.each do |key, tag|
277
+ next unless data.include?(key)
278
+
279
+ xml.tag! tag do
280
+ data_amount = data[key].symbolize_keys
281
+ add_amount(xml, data_amount[:amount].to_i, data_amount)
282
+ end
283
+ end
284
+
285
+ xml.discountName data[:discount_name] if data.include?(:discount_name)
286
+ xml.discountCode data[:discount_code] if data.include?(:discount_code)
287
+
288
+ add_date_element(xml, 'shippingDate', data[:shipping_date]) if data.include?(:shipping_date)
289
+
290
+ if data.include?(:shipping_courier)
291
+ xml.shippingCourier(
292
+ data[:shipping_courier][:priority],
293
+ data[:shipping_courier][:tracking_number],
294
+ data[:shipping_courier][:name]
295
+ )
296
+ end
297
+
298
+ add_optional_data_level_two_and_three(xml, data)
299
+
300
+ if data.include?(:item) && data[:item].kind_of?(Array)
301
+ data[:item].each { |item| add_items_into_level_three_data(xml, item.symbolize_keys) }
302
+ elsif data.include?(:item)
303
+ add_items_into_level_three_data(xml, data[:item].symbolize_keys)
304
+ end
305
+ end
306
+
307
+ def add_items_into_level_three_data(xml, item)
308
+ xml.item do
309
+ xml.description item[:description] if item[:description]
310
+ xml.productCode item[:product_code] if item[:product_code]
311
+ xml.commodityCode item[:commodity_code] if item[:commodity_code]
312
+ xml.quantity item[:quantity] if item[:quantity]
313
+
314
+ {
315
+ unit_cost: 'unitCost',
316
+ item_total: 'itemTotal',
317
+ item_total_with_tax: 'itemTotalWithTax',
318
+ item_discount_amount: 'itemDiscountAmount',
319
+ tax_amount: 'taxAmount'
320
+ }.each do |key, tag|
321
+ next unless item.include?(key)
322
+
323
+ xml.tag! tag do
324
+ data_amount = item[key].symbolize_keys
325
+ add_amount(xml, data_amount[:amount].to_i, data_amount)
326
+ end
327
+ end
328
+ end
329
+ end
330
+
331
+ def add_optional_data_level_two_and_three(xml, data)
332
+ xml.shipFromPostalCode data[:ship_from_postal_code] if data.include?(:ship_from_postal_code)
333
+ xml.destinationPostalCode data[:destination_postal_code] if data.include?(:destination_postal_code)
334
+ xml.destinationCountryCode data[:destination_country_code] if data.include?(:destination_country_code)
335
+ add_date_element(xml, 'orderDate', data[:order_date].symbolize_keys) if data.include?(:order_date)
336
+ xml.taxExempt data[:tax_exempt] if data.include?(:tax_exempt)
337
+ end
338
+
339
+ def order_tag_attributes(options)
340
+ { 'orderCode' => clean_order_id(options[:order_id]), 'installationId' => options[:inst_id] || @options[:inst_id] }.reject { |_, v| !v.present? }
341
+ end
342
+
343
+ def clean_order_id(order_id)
344
+ order_id.to_s.gsub(/(\s|\||<|>|'|")/, '')[0..64]
345
+ end
346
+
347
+ def add_order_content(xml, options)
348
+ return unless options[:order_content]
349
+
350
+ xml.orderContent do
351
+ xml.cdata! options[:order_content]
352
+ end
353
+ end
354
+
355
+ def build_capture_request(money, authorization, options)
356
+ build_order_modify_request(authorization) do |xml|
357
+ xml.capture do
358
+ time = Time.now
359
+ xml.date 'dayOfMonth' => time.day, 'month' => time.month, 'year' => time.year
360
+ add_amount(xml, money, options)
361
+ end
362
+ end
363
+ end
364
+
365
+ def build_void_request(authorization, options)
366
+ if options[:cancel_or_refund]
367
+ build_order_modify_request(authorization, &:cancelOrRefund)
368
+ else
369
+ build_order_modify_request(authorization, &:cancel)
370
+ end
371
+ end
372
+
373
+ def build_refund_request(money, authorization, options)
374
+ build_order_modify_request(authorization) do |xml|
375
+ if options[:cancel_or_refund]
376
+ # Worldpay docs claim amount must be passed. This causes an error.
377
+ xml.cancelOrRefund # { add_amount(xml, money, options.merge(debit_credit_indicator: 'credit')) }
378
+ else
379
+ xml.refund do
380
+ add_amount(xml, money, options.merge(debit_credit_indicator: 'credit'))
381
+ end
382
+ end
383
+ end
384
+ end
385
+
386
+ def build_store_request(credit_card, options)
387
+ build_request do |xml|
388
+ xml.submit do
389
+ xml.paymentTokenCreate do
390
+ add_authenticated_shopper_id(xml, options)
391
+ xml.createToken
392
+ xml.paymentInstrument do
393
+ xml.cardDetails do
394
+ add_card(xml, credit_card, options)
395
+ end
396
+ end
397
+ add_transaction_identifier(xml, options) if network_transaction_id(options)
398
+ end
399
+ end
400
+ end
401
+ end
402
+
403
+ def network_transaction_id(options)
404
+ options[:stored_credential_transaction_id] || options.dig(:stored_credential, :network_transaction_id)
405
+ end
406
+
407
+ def add_transaction_identifier(xml, options)
408
+ xml.storedCredentials 'usage' => 'FIRST' do
409
+ xml.schemeTransactionIdentifier network_transaction_id(options)
410
+ end
411
+ end
412
+
413
+ def build_fast_fund_credit_request(money, payment_method, options)
414
+ build_request do |xml|
415
+ xml.submit do
416
+ xml.order order_tag_attributes(options) do
417
+ xml.description(options[:description].blank? ? 'Fast Fund Credit' : options[:description])
418
+ add_amount(xml, money, options)
419
+ add_order_content(xml, options)
420
+ add_payment_details_for_ff_credit(xml, payment_method, options)
421
+ add_shopper_id(xml, options)
422
+ end
423
+ end
424
+ end
425
+ end
426
+
427
+ def add_payment_details_for_ff_credit(xml, payment_method, options)
428
+ xml.paymentDetails do
429
+ xml.tag! 'FF_DISBURSE-SSL' do
430
+ if payment_method.is_a?(CreditCard)
431
+ add_card_for_ff_credit(xml, payment_method, options)
432
+ else
433
+ add_token_for_ff_credit(xml, payment_method, options)
434
+ end
435
+ end
436
+ end
437
+ end
438
+
439
+ def add_card_for_ff_credit(xml, payment_method, options)
440
+ xml.recipient do
441
+ xml.paymentInstrument do
442
+ xml.cardDetails do
443
+ add_card(xml, payment_method, options)
444
+ end
445
+ end
446
+ end
447
+ end
448
+
449
+ def add_token_for_ff_credit(xml, payment_method, options)
450
+ return unless payment_method.is_a?(String)
451
+
452
+ token_details = token_details_from_authorization(payment_method)
453
+
454
+ xml.tag! 'recipient', 'tokenScope' => token_details[:token_scope] do
455
+ xml.paymentTokenID token_details[:token_id]
456
+ add_authenticated_shopper_id(xml, token_details)
457
+ end
458
+ end
459
+
460
+ def add_additional_3ds_data(xml, options)
461
+ additional_data = { 'dfReferenceId' => options[:session_id] }
462
+ additional_data['challengeWindowSize'] = options[:browser_size] if options[:browser_size]
463
+
464
+ xml.additional3DSData additional_data
465
+ end
466
+
467
+ def add_3ds_exemption(xml, options)
468
+ xml.exemption 'type' => options[:exemption_type], 'placement' => options[:exemption_placement] || 'AUTHORISATION'
469
+ end
470
+
471
+ def add_risk_data(xml, risk_data)
472
+ xml.riskData do
473
+ add_authentication_risk_data(xml, risk_data[:authentication_risk_data])
474
+ add_shopper_account_risk_data(xml, risk_data[:shopper_account_risk_data])
475
+ add_transaction_risk_data(xml, risk_data[:transaction_risk_data])
476
+ end
477
+ end
478
+
479
+ def add_authentication_risk_data(xml, authentication_risk_data)
480
+ return unless authentication_risk_data
481
+
482
+ timestamp = authentication_risk_data.fetch(:authentication_date, {})
483
+
484
+ xml.authenticationRiskData('authenticationMethod' => authentication_risk_data[:authentication_method]) do
485
+ xml.authenticationTimestamp do
486
+ xml.date(
487
+ 'dayOfMonth' => timestamp[:day_of_month],
488
+ 'month' => timestamp[:month],
489
+ 'year' => timestamp[:year],
490
+ 'hour' => timestamp[:hour],
491
+ 'minute' => timestamp[:minute],
492
+ 'second' => timestamp[:second]
493
+ )
494
+ end
495
+ end
496
+ end
497
+
498
+ def add_sub_merchant_data(xml, options)
499
+ xml.subMerchantData do
500
+ xml.pfId options[:pf_id] if options[:pf_id]
501
+ xml.subName options[:sub_name] if options[:sub_name]
502
+ xml.subId options[:sub_id] if options[:sub_id]
503
+ xml.subStreet options[:sub_street] if options[:sub_street]
504
+ xml.subCity options[:sub_city] if options[:sub_city]
505
+ xml.subState options[:sub_state] if options[:sub_state]
506
+ xml.subCountryCode options[:sub_country_code] if options[:sub_country_code]
507
+ xml.subPostalCode options[:sub_postal_code] if options[:sub_postal_code]
508
+ xml.subTaxId options[:sub_tax_id] if options[:sub_tax_id]
509
+ end
510
+ end
511
+
512
+ def add_shopper_account_risk_data(xml, shopper_account_risk_data)
513
+ return unless shopper_account_risk_data
514
+
515
+ data = {
516
+ 'transactionsAttemptedLastDay' => shopper_account_risk_data[:transactions_attempted_last_day],
517
+ 'transactionsAttemptedLastYear' => shopper_account_risk_data[:transactions_attempted_last_year],
518
+ 'purchasesCompletedLastSixMonths' => shopper_account_risk_data[:purchases_completed_last_six_months],
519
+ 'addCardAttemptsLastDay' => shopper_account_risk_data[:add_card_attempts_last_day],
520
+ 'previousSuspiciousActivity' => shopper_account_risk_data[:previous_suspicious_activity],
521
+ 'shippingNameMatchesAccountName' => shopper_account_risk_data[:shipping_name_matches_account_name],
522
+ 'shopperAccountAgeIndicator' => shopper_account_risk_data[:shopper_account_age_indicator],
523
+ 'shopperAccountChangeIndicator' => shopper_account_risk_data[:shopper_account_change_indicator],
524
+ 'shopperAccountPasswordChangeIndicator' => shopper_account_risk_data[:shopper_account_password_change_indicator],
525
+ 'shopperAccountShippingAddressUsageIndicator' => shopper_account_risk_data[:shopper_account_shipping_address_usage_indicator],
526
+ 'shopperAccountPaymentAccountIndicator' => shopper_account_risk_data[:shopper_account_payment_account_indicator]
527
+ }.reject { |_k, v| v.nil? }
528
+
529
+ xml.shopperAccountRiskData(data) do
530
+ add_date_element(xml, 'shopperAccountCreationDate', shopper_account_risk_data[:shopper_account_creation_date])
531
+ add_date_element(xml, 'shopperAccountModificationDate', shopper_account_risk_data[:shopper_account_modification_date])
532
+ add_date_element(xml, 'shopperAccountPasswordChangeDate', shopper_account_risk_data[:shopper_account_password_change_date])
533
+ add_date_element(xml, 'shopperAccountShippingAddressFirstUseDate', shopper_account_risk_data[:shopper_account_shipping_address_first_use_date])
534
+ add_date_element(xml, 'shopperAccountPaymentAccountFirstUseDate', shopper_account_risk_data[:shopper_account_payment_account_first_use_date])
535
+ end
536
+ end
537
+
538
+ def add_transaction_risk_data(xml, transaction_risk_data)
539
+ return unless transaction_risk_data
540
+
541
+ data = {
542
+ 'shippingMethod' => transaction_risk_data[:shipping_method],
543
+ 'deliveryTimeframe' => transaction_risk_data[:delivery_timeframe],
544
+ 'deliveryEmailAddress' => transaction_risk_data[:delivery_email_address],
545
+ 'reorderingPreviousPurchases' => transaction_risk_data[:reordering_previous_purchases],
546
+ 'preOrderPurchase' => transaction_risk_data[:pre_order_purchase],
547
+ 'giftCardCount' => transaction_risk_data[:gift_card_count]
548
+ }.reject { |_k, v| v.nil? }
549
+
550
+ xml.transactionRiskData(data) do
551
+ xml.transactionRiskDataGiftCardAmount do
552
+ amount_hash = {
553
+ 'value' => transaction_risk_data.dig(:transaction_risk_data_gift_card_amount, :value),
554
+ 'currencyCode' => transaction_risk_data.dig(:transaction_risk_data_gift_card_amount, :currency),
555
+ 'exponent' => transaction_risk_data.dig(:transaction_risk_data_gift_card_amount, :exponent)
556
+ }
557
+ debit_credit_indicator = transaction_risk_data.dig(:transaction_risk_data_gift_card_amount, :debit_credit_indicator)
558
+ amount_hash['debitCreditIndicator'] = debit_credit_indicator if debit_credit_indicator
559
+ xml.amount(amount_hash)
560
+ end
561
+ add_date_element(xml, 'transactionRiskDataPreOrderDate', transaction_risk_data[:transaction_risk_data_pre_order_date])
562
+ end
563
+ end
564
+
565
+ def add_date_element(xml, name, date)
566
+ xml.tag! name do
567
+ xml.date('dayOfMonth' => date[:day_of_month], 'month' => date[:month], 'year' => date[:year])
568
+ end
569
+ end
570
+
571
+ def add_amount(xml, money, options)
572
+ currency = options[:currency] || currency(money)
573
+
574
+ amount_hash = {
575
+ :value => localized_amount(money, currency),
576
+ 'currencyCode' => currency,
577
+ 'exponent' => currency_exponent(currency)
578
+ }
579
+
580
+ amount_hash['debitCreditIndicator'] = options[:debit_credit_indicator] if options[:debit_credit_indicator]
581
+
582
+ xml.amount amount_hash
583
+ end
584
+
585
+ def add_payment_method(xml, amount, payment_method, options)
586
+ case options[:payment_type]
587
+ when :pay_as_order
588
+ add_amount_for_pay_as_order(xml, amount, payment_method, options)
589
+ when :network_token
590
+ add_network_tokenization_card(xml, payment_method)
591
+ else
592
+ add_card_or_token(xml, payment_method, options)
593
+ end
594
+ end
595
+
596
+ def add_amount_for_pay_as_order(xml, amount, payment_method, options)
597
+ if options[:merchant_code]
598
+ xml.payAsOrder 'orderCode' => payment_method, 'merchantCode' => options[:merchant_code] do
599
+ add_amount(xml, amount, options)
600
+ end
601
+ else
602
+ xml.payAsOrder 'orderCode' => payment_method do
603
+ add_amount(xml, amount, options)
604
+ end
605
+ end
606
+ end
607
+
608
+ def add_network_tokenization_card(xml, payment_method)
609
+ token_type = NETWORK_TOKEN_TYPE.fetch(payment_method.source, 'NETWORKTOKEN')
610
+
611
+ xml.paymentDetails do
612
+ xml.tag! 'EMVCO_TOKEN-SSL', 'type' => token_type do
613
+ xml.tokenNumber payment_method.number
614
+ xml.expiryDate do
615
+ xml.date(
616
+ 'month' => format(payment_method.month, :two_digits),
617
+ 'year' => format(payment_method.year, :four_digits_year)
618
+ )
619
+ end
620
+ name = card_holder_name(payment_method, options)
621
+ eci = format(payment_method.eci, :two_digits)
622
+ xml.cardHolderName name if name.present?
623
+ xml.cryptogram payment_method.payment_cryptogram
624
+ xml.eciIndicator eci.empty? ? '07' : eci
625
+ end
626
+ end
627
+ end
628
+
629
+ def add_card_or_token(xml, payment_method, options)
630
+ xml.paymentDetails credit_fund_transfer_attribute(options) do
631
+ if options[:payment_type] == :token
632
+ add_token_details(xml, options)
633
+ else
634
+ add_card_details(xml, payment_method, options)
635
+ end
636
+ add_stored_credential_options(xml, options)
637
+ add_shopper_id(xml, options)
638
+ add_three_d_secure(xml, options)
639
+ end
640
+ end
641
+
642
+ def add_token_details(xml, options)
643
+ xml.tag! 'TOKEN-SSL', 'tokenScope' => options[:token_scope] do
644
+ xml.paymentTokenID options[:token_id]
645
+ end
646
+ end
647
+
648
+ def add_card_details(xml, payment_method, options)
649
+ xml.tag! card_code_for(payment_method) do
650
+ add_card(xml, payment_method, options)
651
+ end
652
+ end
653
+
654
+ def add_shopper_id(xml, options)
655
+ if options[:ip] && options[:session_id]
656
+ xml.session 'shopperIPAddress' => options[:ip], 'id' => options[:session_id]
657
+ else
658
+ xml.session 'shopperIPAddress' => options[:ip] if options[:ip]
659
+ xml.session 'id' => options[:session_id] if options[:session_id]
660
+ end
661
+ end
662
+
663
+ def add_three_d_secure(xml, options)
664
+ return unless three_d_secure = options[:three_d_secure]
665
+
666
+ xml.info3DSecure do
667
+ xml.threeDSVersion three_d_secure[:version]
668
+ if three_d_secure[:version] && three_d_secure[:ds_transaction_id]
669
+ xml.dsTransactionId three_d_secure[:ds_transaction_id]
670
+ else
671
+ xml.xid three_d_secure[:xid]
672
+ end
673
+ xml.cavv three_d_secure[:cavv]
674
+ xml.eci three_d_secure[:eci]
675
+ end
676
+ end
677
+
678
+ def add_card(xml, payment_method, options)
679
+ xml.cardNumber payment_method.number
680
+ xml.expiryDate do
681
+ xml.date(
682
+ 'month' => format(payment_method.month, :two_digits),
683
+ 'year' => format(payment_method.year, :four_digits_year)
684
+ )
685
+ end
686
+ name = card_holder_name(payment_method, options)
687
+ xml.cardHolderName name if name.present?
688
+ xml.cvc payment_method.verification_value
689
+
690
+ add_address(xml, (options[:billing_address] || options[:address]), options)
691
+ end
692
+
693
+ def add_stored_credential_options(xml, options = {})
694
+ if options[:stored_credential]
695
+ add_stored_credential_using_normalized_fields(xml, options)
696
+ else
697
+ add_stored_credential_using_gateway_specific_fields(xml, options)
698
+ end
699
+ end
700
+
701
+ def add_stored_credential_using_normalized_fields(xml, options)
702
+ if options[:stored_credential][:initial_transaction]
703
+ xml.storedCredentials 'usage' => 'FIRST'
704
+ else
705
+ reason = case options[:stored_credential][:reason_type]
706
+ when 'installment' then 'INSTALMENT'
707
+ when 'recurring' then 'RECURRING'
708
+ when 'unscheduled' then 'UNSCHEDULED'
709
+ end
710
+
711
+ xml.storedCredentials 'usage' => 'USED', 'merchantInitiatedReason' => reason do
712
+ xml.schemeTransactionIdentifier options[:stored_credential][:network_transaction_id] if options[:stored_credential][:network_transaction_id]
713
+ end
714
+ end
715
+ end
716
+
717
+ def add_stored_credential_using_gateway_specific_fields(xml, options)
718
+ return unless options[:stored_credential_usage]
719
+
720
+ if options[:stored_credential_initiated_reason]
721
+ xml.storedCredentials 'usage' => options[:stored_credential_usage], 'merchantInitiatedReason' => options[:stored_credential_initiated_reason] do
722
+ xml.schemeTransactionIdentifier options[:stored_credential_transaction_id] if options[:stored_credential_transaction_id]
723
+ end
724
+ else
725
+ xml.storedCredentials 'usage' => options[:stored_credential_usage]
726
+ end
727
+ end
728
+
729
+ def add_shopper(xml, options)
730
+ return unless options[:execute_threed] || options[:email] || options[:customer]
731
+
732
+ xml.shopper do
733
+ xml.shopperEmailAddress options[:email] if options[:email]
734
+ add_authenticated_shopper_id(xml, options)
735
+ xml.browser do
736
+ xml.acceptHeader options[:accept_header]
737
+ xml.userAgentHeader options[:user_agent]
738
+ end
739
+ end
740
+ end
741
+
742
+ def add_statement_narrative(xml, options)
743
+ xml.statementNarrative truncate(options[:statement_narrative], 50) if options[:statement_narrative]
744
+ end
745
+
746
+ def add_authenticated_shopper_id(xml, options)
747
+ xml.authenticatedShopperID options[:customer] if options[:customer]
748
+ end
749
+
750
+ def add_address(xml, address, options)
751
+ return unless address
752
+
753
+ address = address_with_defaults(address)
754
+
755
+ xml.cardAddress do
756
+ xml.address do
757
+ if m = /^\s*([^\s]+)\s+(.+)$/.match(address[:name])
758
+ xml.firstName m[1]
759
+ xml.lastName m[2]
760
+ end
761
+ xml.address1 address[:address1]
762
+ xml.address2 address[:address2] if address[:address2]
763
+ xml.postalCode address[:zip]
764
+ xml.city address[:city]
765
+ xml.state address[:state] unless address[:country] != 'US' && options[:execute_threed]
766
+ xml.countryCode address[:country]
767
+ xml.telephoneNumber address[:phone] if address[:phone]
768
+ end
769
+ end
770
+ end
771
+
772
+ def add_hcg_additional_data(xml, options)
773
+ xml.hcgAdditionalData do
774
+ options[:hcg_additional_data].each do |k, v|
775
+ xml.param({ name: k.to_s }, v)
776
+ end
777
+ end
778
+ end
779
+
780
+ def add_instalments_data(xml, options)
781
+ xml.thirdPartyData do
782
+ xml.instalments options[:instalments]
783
+ xml.cpf options[:cpf] if options[:cpf]
784
+ end
785
+ end
786
+
787
+ def add_moto_flag(xml, options)
788
+ xml.dynamicInteractionType 'type' => 'MOTO'
789
+ end
790
+
791
+ def address_with_defaults(address)
792
+ address ||= {}
793
+ address.delete_if { |_, v| v.blank? }
794
+ address.reverse_merge!(default_address)
795
+ end
796
+
797
+ def default_address
798
+ {
799
+ zip: '0000',
800
+ country: 'US',
801
+ city: 'N/A',
802
+ address1: 'N/A'
803
+ }
804
+ end
805
+
806
+ def parse(action, xml)
807
+ xml = xml.strip.gsub(/\&/, '&amp;')
808
+ doc = Nokogiri::XML(xml, &:strict)
809
+ doc.remove_namespaces!
810
+ resp_params = { action: action }
811
+
812
+ parse_elements(doc.root, resp_params)
813
+ extract_issuer_response(doc.root, resp_params)
814
+
815
+ resp_params
816
+ end
817
+
818
+ def extract_issuer_response(doc, response)
819
+ return unless issuer_response = doc.at_xpath('//paymentService//reply//orderStatus//payment//IssuerResponseCode')
820
+
821
+ response[:issuer_response_code] = issuer_response['code']
822
+ response[:issuer_response_description] = issuer_response['description']
823
+ end
824
+
825
+ def parse_elements(node, response)
826
+ node_name = node.name.underscore
827
+ node.attributes.each do |k, v|
828
+ response["#{node_name}_#{k.underscore}".to_sym] = v.value
829
+ end
830
+ if node.elements.empty?
831
+ response[node_name.to_sym] = node.text unless node.text.blank?
832
+ else
833
+ response[node_name.to_sym] = true unless node.name.blank?
834
+ node.elements.each do |childnode|
835
+ parse_elements(childnode, response)
836
+ end
837
+ end
838
+ end
839
+
840
+ def headers(options)
841
+ idempotency_key = options[:idempotency_key]
842
+
843
+ headers = {
844
+ 'Content-Type' => 'text/xml',
845
+ 'Authorization' => encoded_credentials
846
+ }
847
+
848
+ # ensure cookie included on follow-up '3ds' and 'capture_request' calls, using the cookie saved from the preceding response
849
+ # cookie should be present in options on the 3ds and capture calls, but also still saved in the instance var in case
850
+ cookie = options[:cookie] || @cookie || nil
851
+ headers['Cookie'] = cookie if cookie
852
+
853
+ headers['Idempotency-Key'] = idempotency_key if idempotency_key
854
+ headers
855
+ end
856
+
857
+ def commit(action, request, *success_criteria, options)
858
+ xml = ssl_post(url, request, headers(options))
859
+ raw = parse(action, xml)
860
+
861
+ if options[:execute_threed]
862
+ raw[:cookie] = @cookie if defined?(@cookie)
863
+ raw[:session_id] = options[:session_id]
864
+ raw[:is3DSOrder] = true
865
+ end
866
+ success = success_from(action, raw, success_criteria)
867
+ message = message_from(success, raw, success_criteria, action)
868
+
869
+ Response.new(
870
+ success,
871
+ message,
872
+ raw,
873
+ authorization: authorization_from(action, raw, options),
874
+ error_code: error_code_from(success, raw),
875
+ test: test?,
876
+ avs_result: AVSResult.new(code: AVS_CODE_MAP[raw[:avs_result_code_description]]),
877
+ cvv_result: CVVResult.new(CVC_CODE_MAP[raw[:cvc_result_code_description]])
878
+ )
879
+ rescue Nokogiri::SyntaxError
880
+ unparsable_response(xml)
881
+ rescue ActiveMerchant::ResponseError => e
882
+ if e.response.code.to_s == '401'
883
+ return Response.new(false, 'Invalid credentials', {}, test: test?)
884
+ else
885
+ raise e
886
+ end
887
+ end
888
+
889
+ def url
890
+ test? ? self.test_url : self.live_url
891
+ end
892
+
893
+ def unparsable_response(raw_response)
894
+ message = 'Unparsable response received from Worldpay. Please contact Worldpay if you continue to receive this message.'
895
+ message += " (The raw response returned by the API was: #{raw_response.inspect})"
896
+ return Response.new(false, message)
897
+ end
898
+
899
+ # Override the regular handle response so we can access the headers
900
+ # Set-Cookie value is needed for 3DS transactions
901
+ def handle_response(response)
902
+ case response.code.to_i
903
+ when 200...300
904
+ cookie = response.header['Set-Cookie']&.match('^[^;]*')
905
+ @cookie = cookie[0] if cookie
906
+ response.body
907
+ else
908
+ raise ResponseError.new(response)
909
+ end
910
+ end
911
+
912
+ def success_from(action, raw, success_criteria)
913
+ success_criteria_success?(raw, success_criteria) || action_success?(action, raw)
914
+ end
915
+
916
+ def message_from(success, raw, success_criteria, action)
917
+ return 'SUCCESS' if success
918
+
919
+ raw[:iso8583_return_code_description] || raw[:error] || required_status_message(raw, success_criteria, action) || raw[:issuer_response_description]
920
+ end
921
+
922
+ # success_criteria can be:
923
+ # - a string or an array of strings (if one of many responses)
924
+ # - An array of strings if one of many responses could be considered a
925
+ # success.
926
+ def success_criteria_success?(raw, success_criteria)
927
+ return if raw[:error]
928
+
929
+ raw[:ok].present? || (success_criteria.include?(raw[:last_event]) if raw[:last_event])
930
+ end
931
+
932
+ def action_success?(action, raw)
933
+ case action
934
+ when 'store'
935
+ raw[:token].present?
936
+ when 'direct_inquiry'
937
+ raw[:last_event].present?
938
+ else
939
+ false
940
+ end
941
+ end
942
+
943
+ def error_code_from(success, raw)
944
+ raw[:iso8583_return_code_code] || raw[:error_code] || nil unless success == 'SUCCESS'
945
+ end
946
+
947
+ def required_status_message(raw, success_criteria, action)
948
+ return if success_criteria.include?(raw[:last_event])
949
+ return unless %w[cancel refund inquiry credit fast_credit].include?(action)
950
+
951
+ "A transaction status of #{success_criteria.collect { |c| "'#{c}'" }.join(' or ')} is required."
952
+ end
953
+
954
+ def authorization_from(action, raw, options)
955
+ order_id = order_id_from(raw)
956
+
957
+ case action
958
+ when 'store'
959
+ authorization_from_token_details(
960
+ order_id: order_id,
961
+ token_id: raw[:payment_token_id],
962
+ token_scope: 'shopper',
963
+ customer: options[:customer]
964
+ )
965
+ else
966
+ order_id
967
+ end
968
+ end
969
+
970
+ def order_id_from(raw)
971
+ pair = raw.detect { |k, _v| k.to_s =~ /_order_code$/ }
972
+ (pair ? pair.last : nil)
973
+ end
974
+
975
+ def authorization_from_token_details(options = {})
976
+ [options[:order_id], options[:token_id], options[:token_scope], options[:customer]].join('|')
977
+ end
978
+
979
+ def order_id_from_authorization(authorization)
980
+ token_details_from_authorization(authorization)[:order_id]
981
+ end
982
+
983
+ def token_details_from_authorization(authorization)
984
+ order_id, token_id, token_scope, customer = authorization.split('|')
985
+
986
+ token_details = {}
987
+ token_details[:order_id] = order_id if order_id.present?
988
+ token_details[:token_id] = token_id if token_id.present?
989
+ token_details[:token_scope] = token_scope if token_scope.present?
990
+ token_details[:customer] = customer if customer.present?
991
+
992
+ token_details
993
+ end
994
+
995
+ def payment_details(payment_method)
996
+ case payment_method
997
+ when String
998
+ token_type_and_details(payment_method)
999
+ else
1000
+ type = network_token?(payment_method) ? :network_token : :credit
1001
+
1002
+ { payment_type: type }
1003
+ end
1004
+ end
1005
+
1006
+ def network_token?(payment_method)
1007
+ payment_method.respond_to?(:source) &&
1008
+ payment_method.respond_to?(:payment_cryptogram) &&
1009
+ payment_method.respond_to?(:eci)
1010
+ end
1011
+
1012
+ def token_type_and_details(token)
1013
+ token_details = token_details_from_authorization(token)
1014
+ token_details[:payment_type] = token_details.has_key?(:token_id) ? :token : :pay_as_order
1015
+
1016
+ token_details
1017
+ end
1018
+
1019
+ def credit_fund_transfer_attribute(options)
1020
+ return unless options[:credit]
1021
+
1022
+ { 'action' => 'REFUND' }
1023
+ end
1024
+
1025
+ def encoded_credentials
1026
+ credentials = "#{@options[:login]}:#{@options[:password]}"
1027
+ "Basic #{[credentials].pack('m').strip}"
1028
+ end
1029
+
1030
+ def currency_exponent(currency)
1031
+ return 0 if non_fractional_currency?(currency)
1032
+ return 3 if three_decimal_currency?(currency)
1033
+
1034
+ return 2
1035
+ end
1036
+
1037
+ def card_code_for(payment_method)
1038
+ CARD_CODES[card_brand(payment_method)] || CARD_CODES['unknown']
1039
+ end
1040
+
1041
+ def eligible_for_0_auth?(payment_method, options = {})
1042
+ payment_method.is_a?(CreditCard) && %w(visa master).include?(payment_method.brand) && options[:zero_dollar_auth]
1043
+ end
1044
+
1045
+ def card_holder_name(payment_method, options)
1046
+ test? && options[:execute_threed] && !options[:three_ds_version]&.start_with?('2') ? '3D' : payment_method.name
1047
+ end
1048
+ end
1049
+ end
1050
+ end