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,718 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ # This module is included in both PaypalGateway and PaypalExpressGateway
4
+ module PaypalCommonAPI
5
+ include Empty
6
+
7
+ API_VERSION = '124'
8
+ API_VERSION_3DS2 = '214.0'
9
+
10
+ URLS = {
11
+ :test => { :certificate => 'https://api.sandbox.paypal.com/2.0/',
12
+ :signature => 'https://api-3t.sandbox.paypal.com/2.0/' },
13
+ :live => { :certificate => 'https://api.paypal.com/2.0/',
14
+ :signature => 'https://api-3t.paypal.com/2.0/' }
15
+ }
16
+
17
+ PAYPAL_NAMESPACE = 'urn:ebay:api:PayPalAPI'
18
+ EBAY_NAMESPACE = 'urn:ebay:apis:eBLBaseComponents'
19
+
20
+ ENVELOPE_NAMESPACES = { 'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema',
21
+ 'xmlns:env' => 'http://schemas.xmlsoap.org/soap/envelope/',
22
+ 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance'
23
+ }
24
+ CREDENTIALS_NAMESPACES = { 'xmlns' => PAYPAL_NAMESPACE,
25
+ 'xmlns:n1' => EBAY_NAMESPACE,
26
+ 'env:mustUnderstand' => '0'
27
+ }
28
+
29
+ AUSTRALIAN_STATES = {
30
+ 'ACT' => 'Australian Capital Territory',
31
+ 'NSW' => 'New South Wales',
32
+ 'NT' => 'Northern Territory',
33
+ 'QLD' => 'Queensland',
34
+ 'SA' => 'South Australia',
35
+ 'TAS' => 'Tasmania',
36
+ 'VIC' => 'Victoria',
37
+ 'WA' => 'Western Australia'
38
+ }
39
+
40
+ SUCCESS_CODES = [ 'Success', 'SuccessWithWarning' ]
41
+
42
+ FRAUD_REVIEW_CODE = "11610"
43
+
44
+ STANDARD_ERROR_CODE_MAPPING = {
45
+ '15005' => :card_declined,
46
+ '10754' => :card_declined,
47
+ '10752' => :card_declined,
48
+ '10759' => :card_declined,
49
+ '10761' => :card_declined,
50
+ '15002' => :card_declined,
51
+ '11084' => :card_declined,
52
+ '15004' => :incorrect_cvc,
53
+ '10762' => :invalid_cvc,
54
+ }
55
+
56
+ STANDARD_ERROR_CODE_MAPPING.default = :processing_error
57
+
58
+ def self.included(base)
59
+ base.default_currency = 'USD'
60
+ base.cattr_accessor :pem_file
61
+ base.cattr_accessor :signature
62
+ base.live_url = URLS[:live][:signature]
63
+ base.test_url = URLS[:test][:signature]
64
+ end
65
+
66
+ # The gateway must be configured with either your PayPal PEM file
67
+ # or your PayPal API Signature. Only one is required.
68
+ #
69
+ # <tt>:pem</tt> The text of your PayPal PEM file. Note
70
+ # this is not the path to file, but its
71
+ # contents. If you are only using one PEM
72
+ # file on your site you can declare it
73
+ # globally and then you won't need to
74
+ # include this option
75
+ #
76
+ # <tt>:signature</tt> The text of your PayPal signature.
77
+ # If you are only using one API Signature
78
+ # on your site you can declare it
79
+ # globally and then you won't need to
80
+ # include this option
81
+ def initialize(options = {})
82
+ requires!(options, :login, :password)
83
+
84
+ headers = {'X-PP-AUTHORIZATION' => options.delete(:auth_signature), 'X-PAYPAL-MESSAGE-PROTOCOL' => 'SOAP11'} if options[:auth_signature]
85
+ options = {
86
+ :pem => pem_file,
87
+ :signature => signature,
88
+ :headers => headers || {}
89
+ }.update(options)
90
+
91
+
92
+ if options[:pem].blank? && options[:signature].blank?
93
+ raise ArgumentError, "An API Certificate or API Signature is required to make requests to PayPal"
94
+ end
95
+
96
+ super(options)
97
+ end
98
+
99
+ def reauthorize(money, authorization, options = {})
100
+ commit 'DoReauthorization', build_reauthorize_request(money, authorization, options)
101
+ end
102
+
103
+ def capture(money, authorization, options = {})
104
+ commit 'DoCapture', build_capture_request(money, authorization, options)
105
+ end
106
+
107
+ # Transfer money to one or more recipients.
108
+ #
109
+ # gateway.transfer 1000, 'bob@example.com',
110
+ # :subject => "The money I owe you", :note => "Sorry it's so late"
111
+ #
112
+ # gateway.transfer [1000, 'fred@example.com'],
113
+ # [2450, 'wilma@example.com', :note => 'You will receive another payment on 3/24'],
114
+ # [2000, 'barney@example.com'],
115
+ # :subject => "Your Earnings", :note => "Thanks for your business."
116
+ #
117
+ def transfer(*args)
118
+ commit 'MassPay', build_mass_pay_request(*args)
119
+ end
120
+
121
+ def void(authorization, options = {})
122
+ commit 'DoVoid', build_void_request(authorization, options)
123
+ end
124
+
125
+ # Refunds a transaction.
126
+ #
127
+ # For a full refund pass nil for the amount:
128
+ #
129
+ # gateway.refund nil, 'G39883289DH238'
130
+ #
131
+ # This will automatically make the :refund_type be "Full".
132
+ #
133
+ # For a partial refund just pass the amount as usual:
134
+ #
135
+ # gateway.refund 100, 'UBU83983N920'
136
+ #
137
+ def refund(money, identification, options = {})
138
+ commit 'RefundTransaction', build_refund_request(money, identification, options)
139
+ end
140
+
141
+ def credit(money, identification, options = {})
142
+ ActiveMerchant.deprecated Gateway::CREDIT_DEPRECATION_MESSAGE
143
+ refund(money, identification, options)
144
+ end
145
+
146
+ # ==== For full documentation see {Paypal API Reference:}[https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_api_soap_r_DoReferenceTransaction]
147
+ # ==== Parameter:
148
+ # * <tt>:money</tt> -- (Required) The amount of this new transaction,
149
+ # required fo the payment details portion of this request
150
+ #
151
+ # ==== Options:
152
+ # * <tt>:reference_id</tt> -- (Required) A transaction ID from a previous purchase, such as a credit card charge using the DoDirectPayment API, or a billing agreement ID.
153
+ # * <tt>:payment_action</tt> -- (Optional) How you want to obtain payment. It is one of the following values:
154
+ #
155
+ # Authorization – This payment is a basic authorization subject to settlement with PayPal Authorization and Capture.
156
+ # Sale – This is a final sale for which you are requesting payment.
157
+ #
158
+ # * <tt>:ip_address</tt> -- (Optional) IP address of the buyer’s browser.
159
+ # Note: PayPal records this IP addresses as a means to detect possible fraud.
160
+ # * <tt>:req_confirm_shipping</tt> -- Whether you require that the buyer’s shipping address on file with PayPal be a confirmed address. You must have permission from PayPal to not require a confirmed address. It is one of the following values:
161
+ #
162
+ # 0 – You do not require that the buyer’s shipping address be a confirmed address.
163
+ # 1 – You require that the buyer’s shipping address be a confirmed address.
164
+ #
165
+ # * <tt>:merchant_session_id</tt> -- (Optional) Your buyer session identification token.
166
+ # * <tt>:return_fmf_details</tt> -- (Optional) Flag to indicate whether you want the results returned by Fraud Management Filters. By default, you do not receive this information. It is one of the following values:
167
+ #
168
+ # 0 – Do not receive FMF details (default)
169
+ # 1 – Receive FMF details
170
+ #
171
+ # * <tt>:soft_descriptor</tt> -- (Optional) Per transaction description of the payment that is passed to the consumer’s credit card statement. If the API request provides a value for the soft descriptor field, the full descriptor displayed on the buyer’s statement has the following format:
172
+ #
173
+ # <PP * | PAYPAL *><Merchant descriptor as set in the Payment Receiving Preferences><1 space><soft descriptor>
174
+ # The soft descriptor can contain only the following characters:
175
+ #
176
+ # Alphanumeric characters
177
+ # - (dash)
178
+ # * (asterisk)
179
+ # . (period)
180
+ # {space}
181
+ #
182
+ def reference_transaction(money, options = {})
183
+ requires!(options, :reference_id)
184
+ commit 'DoReferenceTransaction', build_reference_transaction_request(money, options)
185
+ end
186
+
187
+ def transaction_details(transaction_id)
188
+ commit 'GetTransactionDetails', build_get_transaction_details(transaction_id)
189
+ end
190
+
191
+ # ==== For full documentation see {PayPal API Reference}[https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_api_soap_r_TransactionSearch]
192
+ # ==== Options:
193
+ # * <tt>:payer </tt> -- (Optional) Search by the buyer’s email address.
194
+ # * <tt>:receipt_id </tt> -- (Optional) Search by the PayPal Account Optional receipt ID.
195
+ # * <tt>:receiver </tt> -- (Optional) Search by the receiver’s email address. If the merchant account has only one email address, this is the primary email. It can also be a non-primary email address.
196
+ # * <tt>:transaction_id</tt> -- (Optional) Search by the transaction ID. The returned results are from the merchant’s transaction records.
197
+ # * <tt>:invoice_id</tt> -- (Optional) Search by invoice identification key, as set by you for the original transaction. This field searches the records for items the merchant sells, not the items purchased.
198
+ # * <tt>:card_number </tt> -- (Optional) Search by credit card number, as set by you for the original transaction. This field searches the records for items the merchant sells, not the items purchased.
199
+ # * <tt>:auction_item_number </tt> -- (Optional) Search by auction item number of the purchased goods.
200
+ # * <tt>:transaction_class </tt> -- (Optional) Search by classification of transaction. Some kinds of possible classes of transactions are not searchable with this field. You cannot search for bank transfer withdrawals, for example. It is one of the following values:
201
+ # All – All transaction classifications
202
+ # Sent – Only payments sent
203
+ # Received – Only payments received
204
+ # MassPay – Only mass payments
205
+ # MoneyRequest – Only money requests
206
+ # FundsAdded – Only funds added to balance
207
+ # FundsWithdrawn – Only funds withdrawn from balance
208
+ # Referral – Only transactions involving referrals
209
+ # Fee – Only transactions involving fees
210
+ # Subscription – Only transactions involving subscriptions
211
+ # Dividend – Only transactions involving dividends
212
+ # Billpay – Only transactions involving BillPay Transactions
213
+ # Refund – Only transactions involving funds
214
+ # CurrencyConversions – Only transactions involving currency conversions
215
+ # BalanceTransfer – Only transactions involving balance transfers
216
+ # Reversal – Only transactions involving BillPay reversals
217
+ # Shipping – Only transactions involving UPS shipping fees
218
+ # BalanceAffecting – Only transactions that affect the account balance
219
+ # ECheck – Only transactions involving eCheck
220
+ #
221
+ # * <tt>:currency_code </tt> -- (Optional) Search by currency code.
222
+ # * <tt>:status</tt> -- (Optional) Search by transaction status. It is one of the following values:
223
+ # One of:
224
+ # Pending – The payment is pending. The specific reason the payment is pending is returned by the GetTransactionDetails API PendingReason field.
225
+ # Processing – The payment is being processed.
226
+ # Success – The payment has been completed and the funds have been added successfully to your account balance.
227
+ # Denied – You denied the payment. This happens only if the payment was previously pending.
228
+ # Reversed – A payment was reversed due to a chargeback or other type of reversal. The funds have been removed from your account balance and returned to the buyer.
229
+ #
230
+ def transaction_search(options)
231
+ requires!(options, :start_date)
232
+ commit 'TransactionSearch', build_transaction_search(options)
233
+ end
234
+
235
+ # ==== Parameters:
236
+ # * <tt>:return_all_currencies</tt> -- Either '1' or '0'
237
+ # 0 – Return only the balance for the primary currency holding.
238
+ # 1 – Return the balance for each currency holding.
239
+ #
240
+ def balance(return_all_currencies = false)
241
+ clean_currency_argument = case return_all_currencies
242
+ when 1, '1' , true; '1'
243
+ else
244
+ '0'
245
+ end
246
+ commit 'GetBalance', build_get_balance(clean_currency_argument)
247
+ end
248
+
249
+ # DoAuthorization takes the transaction_id returned when you call
250
+ # DoExpressCheckoutPayment with a PaymentAction of 'Order'.
251
+ # When you did that, you created an order authorization subject to settlement
252
+ # with PayPal DoAuthorization and DoCapture
253
+ #
254
+ # ==== Parameters:
255
+ # * <tt>:transaction_id</tt> -- The ID returned by DoExpressCheckoutPayment with a PaymentAction of 'Order'.
256
+ # * <tt>:money</tt> -- The amount of money to be authorized for this purchase.
257
+ #
258
+ def authorize_transaction(transaction_id, money, options = {})
259
+ commit 'DoAuthorization', build_do_authorize(transaction_id, money, options)
260
+ end
261
+
262
+ # The ManagePendingTransactionStatus API operation accepts or denies a
263
+ # pending transaction held by Fraud Management Filters.
264
+ #
265
+ # ==== Parameters:
266
+ # * <tt>:transaction_id</tt> -- The ID of the transaction held by Fraud Management Filters.
267
+ # * <tt>:action</tt> -- Either 'Accept' or 'Deny'
268
+ #
269
+ def manage_pending_transaction(transaction_id, action)
270
+ commit 'ManagePendingTransactionStatus', build_manage_pending_transaction_status(transaction_id, action)
271
+ end
272
+
273
+ def supports_scrubbing?
274
+ true
275
+ end
276
+
277
+ def scrub(transcript)
278
+ transcript.
279
+ gsub(%r((<n1:Password>).+(</n1:Password>)), '\1[FILTERED]\2').
280
+ gsub(%r((<n1:Username>).+(</n1:Username>)), '\1[FILTERED]\2').
281
+ gsub(%r((<n1:Signature>).+(</n1:Signature>)), '\1[FILTERED]\2').
282
+ gsub(%r((<n2:CreditCardNumber>).+(</n2:CreditCardNumber)), '\1[FILTERED]\2').
283
+ gsub(%r((<n2:CVV2>)\d+(</n2:CVV2)), '\1[FILTERED]\2')
284
+ end
285
+
286
+ private
287
+
288
+ def build_request_wrapper(action, options = {})
289
+ xml = Builder::XmlMarkup.new :indent => 2
290
+ xml.tag! action + 'Req', 'xmlns' => PAYPAL_NAMESPACE do
291
+ xml.tag! action + 'Request', 'xmlns:n2' => EBAY_NAMESPACE do
292
+ xml.tag! 'n2:Version', API_VERSION
293
+ if options[:request_details]
294
+ xml.tag! 'n2:' + action + 'RequestDetails' do
295
+ yield(xml)
296
+ end
297
+ else
298
+ yield(xml)
299
+ end
300
+ end
301
+ end
302
+ xml.target!
303
+ end
304
+
305
+ def build_do_authorize(transaction_id, money, options = {})
306
+ build_request_wrapper('DoAuthorization') do |xml|
307
+ xml.tag! 'TransactionID', transaction_id
308
+ xml.tag! 'Amount', amount(money), 'currencyID' => options[:currency] || currency(money)
309
+ end
310
+ end
311
+
312
+ def build_reauthorize_request(money, authorization, options)
313
+ xml = Builder::XmlMarkup.new
314
+
315
+ xml.tag! 'DoReauthorizationReq', 'xmlns' => PAYPAL_NAMESPACE do
316
+ xml.tag! 'DoReauthorizationRequest', 'xmlns:n2' => EBAY_NAMESPACE do
317
+ xml.tag! 'n2:Version', API_VERSION
318
+ xml.tag! 'AuthorizationID', authorization
319
+ xml.tag! 'Amount', amount(money), 'currencyID' => options[:currency] || currency(money)
320
+ end
321
+ end
322
+
323
+ xml.target!
324
+ end
325
+
326
+ def build_capture_request(money, authorization, options)
327
+ xml = Builder::XmlMarkup.new
328
+
329
+ xml.tag! 'DoCaptureReq', 'xmlns' => PAYPAL_NAMESPACE do
330
+ xml.tag! 'DoCaptureRequest', 'xmlns:n2' => EBAY_NAMESPACE do
331
+ xml.tag! 'n2:Version', API_VERSION
332
+ xml.tag! 'AuthorizationID', authorization
333
+ xml.tag! 'Amount', amount(money), 'currencyID' => options[:currency] || currency(money)
334
+ xml.tag! 'CompleteType', options[:complete_type] || 'Complete'
335
+ xml.tag! 'InvoiceID', options[:order_id] unless options[:order_id].blank?
336
+ xml.tag! 'Note', options[:description]
337
+ end
338
+ end
339
+
340
+ xml.target!
341
+ end
342
+
343
+ def build_refund_request(money, identification, options)
344
+ xml = Builder::XmlMarkup.new
345
+
346
+ xml.tag! 'RefundTransactionReq', 'xmlns' => PAYPAL_NAMESPACE do
347
+ xml.tag! 'RefundTransactionRequest', 'xmlns:n2' => EBAY_NAMESPACE do
348
+ xml.tag! 'n2:Version', API_VERSION
349
+ xml.tag! 'TransactionID', identification
350
+ xml.tag! 'Amount', amount(money), 'currencyID' => (options[:currency] || currency(money)) if money.present?
351
+ xml.tag! 'RefundType', (options[:refund_type] || (money.present? ? 'Partial' : 'Full'))
352
+ xml.tag! 'Memo', options[:note] unless options[:note].blank?
353
+ end
354
+ end
355
+
356
+ xml.target!
357
+ end
358
+
359
+ def build_void_request(authorization, options)
360
+ xml = Builder::XmlMarkup.new
361
+
362
+ xml.tag! 'DoVoidReq', 'xmlns' => PAYPAL_NAMESPACE do
363
+ xml.tag! 'DoVoidRequest', 'xmlns:n2' => EBAY_NAMESPACE do
364
+ xml.tag! 'n2:Version', API_VERSION
365
+ xml.tag! 'AuthorizationID', authorization
366
+ xml.tag! 'Note', options[:description]
367
+ end
368
+ end
369
+
370
+ xml.target!
371
+ end
372
+
373
+ def build_mass_pay_request(*args)
374
+ default_options = args.last.is_a?(Hash) ? args.pop : {}
375
+ recipients = args.first.is_a?(Array) ? args : [args]
376
+ receiver_type = default_options[:receiver_type]
377
+
378
+ xml = Builder::XmlMarkup.new
379
+
380
+ xml.tag! 'MassPayReq', 'xmlns' => PAYPAL_NAMESPACE do
381
+ xml.tag! 'MassPayRequest', 'xmlns:n2' => EBAY_NAMESPACE do
382
+ xml.tag! 'n2:Version', API_VERSION
383
+ xml.tag! 'EmailSubject', default_options[:subject] if default_options[:subject]
384
+ xml.tag! 'ReceiverType', receiver_type if receiver_type
385
+ recipients.each do |money, recipient, options|
386
+ options ||= default_options
387
+ xml.tag! 'MassPayItem' do
388
+ if(!receiver_type || receiver_type == 'EmailAddress')
389
+ xml.tag! 'ReceiverEmail', recipient
390
+ elsif receiver_type == 'UserID'
391
+ xml.tag! 'ReceiverID', recipient
392
+ else
393
+ raise ArgumentError.new("Unknown receiver_type: #{receiver_type}")
394
+ end
395
+ xml.tag! 'Amount', amount(money), 'currencyID' => (options[:currency] || currency(money))
396
+ xml.tag! 'Note', options[:note] if options[:note]
397
+ xml.tag! 'UniqueId', options[:unique_id] if options[:unique_id]
398
+ end
399
+ end
400
+ end
401
+ end
402
+
403
+ xml.target!
404
+ end
405
+
406
+ def build_manage_pending_transaction_status(transaction_id, action)
407
+ build_request_wrapper('ManagePendingTransactionStatus') do |xml|
408
+ xml.tag! 'TransactionID', transaction_id
409
+ xml.tag! 'Action', action
410
+ end
411
+ end
412
+
413
+ def build_reference_transaction_request(money, options)
414
+ opts = options.dup
415
+ opts[:ip_address] ||= opts[:ip]
416
+ currency_code = opts[:currency] || currency(money)
417
+ reference_transaction_optional_fields = %w{ n2:ReferenceID n2:PaymentAction
418
+ n2:PaymentType n2:IPAddress
419
+ n2:ReqConfirmShipping n2:MerchantSessionId
420
+ n2:ReturnFMFDetails n2:SoftDescriptor }
421
+ build_request_wrapper('DoReferenceTransaction', :request_details => true) do |xml|
422
+ add_optional_fields(xml, reference_transaction_optional_fields, opts)
423
+ add_payment_details(xml, money, currency_code, opts)
424
+ end
425
+ end
426
+
427
+ def build_get_transaction_details(transaction_id)
428
+ build_request_wrapper('GetTransactionDetails') do |xml|
429
+ xml.tag! 'TransactionID', transaction_id
430
+ end
431
+ end
432
+
433
+ def build_transaction_search(options)
434
+ currency_code = options[:currency_code]
435
+ currency_code ||= currency(options[:amount]) if options[:amount]
436
+ transaction_search_optional_fields = %w{ Payer ReceiptID Receiver
437
+ TransactionID InvoiceID CardNumber
438
+ AuctionItemNumber TransactionClass
439
+ CurrencyCode Status ProfileID }
440
+ build_request_wrapper('TransactionSearch') do |xml|
441
+ xml.tag! 'StartDate', date_to_iso(options[:start_date])
442
+ xml.tag! 'EndDate', date_to_iso(options[:end_date]) unless options[:end_date].blank?
443
+ add_optional_fields(xml, transaction_search_optional_fields, options)
444
+ xml.tag! 'Amount', localized_amount(options[:amount], currency_code), 'currencyID' => currency_code unless options[:amount].blank?
445
+ end
446
+ end
447
+
448
+
449
+ def build_get_balance(return_all_currencies)
450
+ build_request_wrapper('GetBalance') do |xml|
451
+ xml.tag! 'ReturnAllCurrencies', return_all_currencies unless return_all_currencies.nil?
452
+ end
453
+ end
454
+
455
+ def parse(action, xml)
456
+ legacy_hash = legacy_parse(action, xml)
457
+ xml = strip_attributes(xml)
458
+ hash = Hash.from_xml(xml)
459
+ hash = hash.fetch('Envelope').fetch('Body').fetch("#{action}Response")
460
+ hash = hash["#{action}ResponseDetails"] if hash["#{action}ResponseDetails"]
461
+
462
+ legacy_hash.merge(hash)
463
+ rescue IndexError
464
+ legacy_hash.merge(hash['Envelope']['Body'])
465
+ end
466
+
467
+ def strip_attributes(xml)
468
+ xml = REXML::Document.new(xml)
469
+ REXML::XPath.each(xml, '//SOAP-ENV:Envelope//*[@*]') do |el|
470
+ el.attributes.each_attribute { |a| a.remove }
471
+ end
472
+ xml.to_s
473
+ end
474
+
475
+ def legacy_parse(action, xml)
476
+ response = {}
477
+
478
+ error_messages = []
479
+ error_codes = []
480
+
481
+ xml = REXML::Document.new(xml)
482
+ if root = REXML::XPath.first(xml, "//#{action}Response")
483
+ root.elements.each do |node|
484
+ case node.name
485
+ when 'Errors'
486
+ short_message = nil
487
+ long_message = nil
488
+
489
+ node.elements.each do |child|
490
+ case child.name
491
+ when "LongMessage"
492
+ long_message = child.text unless child.text.blank?
493
+ when "ShortMessage"
494
+ short_message = child.text unless child.text.blank?
495
+ when "ErrorCode"
496
+ error_codes << child.text unless child.text.blank?
497
+ end
498
+ end
499
+
500
+ if message = long_message || short_message
501
+ error_messages << message
502
+ end
503
+ else
504
+ legacy_parse_element(response, node)
505
+ end
506
+ end
507
+ response[:message] = error_messages.uniq.join(". ") unless error_messages.empty?
508
+ response[:error_codes] = error_codes.uniq.join(",") unless error_codes.empty?
509
+ elsif root = REXML::XPath.first(xml, "//SOAP-ENV:Fault")
510
+ legacy_parse_element(response, root)
511
+ response[:message] = "#{response[:faultcode]}: #{response[:faultstring]} - #{response[:detail]}"
512
+ end
513
+
514
+ response
515
+ end
516
+
517
+ def legacy_parse_element(response, node)
518
+ if node.has_elements?
519
+ node.elements.each{|e| legacy_parse_element(response, e) }
520
+ else
521
+ response[node.name.underscore.to_sym] = node.text
522
+ node.attributes.each do |k, v|
523
+ response["#{node.name.underscore}_#{k.underscore}".to_sym] = v if k == 'currencyID'
524
+ end
525
+ end
526
+ end
527
+
528
+ def build_request(body)
529
+ xml = Builder::XmlMarkup.new
530
+
531
+ xml.instruct!
532
+ xml.tag! 'env:Envelope', ENVELOPE_NAMESPACES do
533
+ xml.tag! 'env:Header' do
534
+ add_credentials(xml) unless @options[:headers] && @options[:headers]['X-PP-AUTHORIZATION']
535
+ end
536
+
537
+ xml.tag! 'env:Body' do
538
+ xml << body
539
+ end
540
+ end
541
+ xml.target!
542
+ end
543
+
544
+ def add_credentials(xml)
545
+ xml.tag! 'RequesterCredentials', CREDENTIALS_NAMESPACES do
546
+ xml.tag! 'n1:Credentials' do
547
+ xml.tag! 'n1:Username', @options[:login]
548
+ xml.tag! 'n1:Password', @options[:password]
549
+ xml.tag! 'n1:Subject', @options[:subject]
550
+ xml.tag! 'n1:Signature', @options[:signature] unless @options[:signature].blank?
551
+ end
552
+ end
553
+ end
554
+
555
+ def add_address(xml, element, address)
556
+ return if address.nil?
557
+ xml.tag! element do
558
+ xml.tag! 'n2:Name', address[:name]
559
+ xml.tag! 'n2:Street1', address[:address1]
560
+ xml.tag! 'n2:Street2', address[:address2]
561
+ xml.tag! 'n2:CityName', address[:city]
562
+ xml.tag! 'n2:StateOrProvince', address[:state].blank? ? 'N/A' : address[:state]
563
+ xml.tag! 'n2:Country', address[:country]
564
+ xml.tag! 'n2:Phone', address[:phone] unless address[:phone].blank?
565
+ xml.tag! 'n2:PostalCode', address[:zip]
566
+ end
567
+ end
568
+
569
+ def add_payment_details_items_xml(xml, options, currency_code)
570
+ options[:items].each do |item|
571
+ xml.tag! 'n2:PaymentDetailsItem' do
572
+ xml.tag! 'n2:Name', item[:name]
573
+ xml.tag! 'n2:Number', item[:number]
574
+ xml.tag! 'n2:Quantity', item[:quantity]
575
+ if item[:amount]
576
+ xml.tag! 'n2:Amount', item_amount(item[:amount], currency_code), 'currencyID' => currency_code
577
+ end
578
+ xml.tag! 'n2:Description', item[:description]
579
+ xml.tag! 'n2:ItemURL', item[:url]
580
+ xml.tag! 'n2:ItemCategory', item[:category] if item[:category]
581
+ end
582
+ end
583
+ end
584
+
585
+ def add_payment_details(xml, money, currency_code, options = {})
586
+ xml.tag! 'n2:PaymentDetails' do
587
+ xml.tag! 'n2:OrderTotal', localized_amount(money, currency_code), 'currencyID' => currency_code
588
+
589
+ # All of the values must be included together and add up to the order total
590
+ if [:subtotal, :shipping, :handling, :tax].all?{ |o| options[o].present? }
591
+ xml.tag! 'n2:ItemTotal', localized_amount(options[:subtotal], currency_code), 'currencyID' => currency_code
592
+ xml.tag! 'n2:ShippingTotal', localized_amount(options[:shipping], currency_code),'currencyID' => currency_code
593
+ xml.tag! 'n2:HandlingTotal', localized_amount(options[:handling], currency_code),'currencyID' => currency_code
594
+ xml.tag! 'n2:TaxTotal', localized_amount(options[:tax], currency_code), 'currencyID' => currency_code
595
+ end
596
+
597
+ xml.tag! 'n2:InsuranceTotal', localized_amount(options[:insurance_total], currency_code),'currencyID' => currency_code unless options[:insurance_total].blank?
598
+ xml.tag! 'n2:ShippingDiscount', localized_amount(options[:shipping_discount], currency_code),'currencyID' => currency_code unless options[:shipping_discount].blank?
599
+ xml.tag! 'n2:InsuranceOptionOffered', options[:insurance_option_offered] if options.has_key?(:insurance_option_offered)
600
+
601
+ xml.tag! 'n2:OrderDescription', options[:description] unless options[:description].blank?
602
+
603
+ # Custom field Character length and limitations: 256 single-byte alphanumeric characters
604
+ xml.tag! 'n2:Custom', options[:custom] unless options[:custom].blank?
605
+
606
+ xml.tag! 'n2:InvoiceID', (options[:order_id] || options[:invoice_id]) unless (options[:order_id] || options[:invoice_id]).blank?
607
+ add_button_source(xml)
608
+
609
+ # The notify URL applies only to DoExpressCheckoutPayment.
610
+ # This value is ignored when set in SetExpressCheckout or GetExpressCheckoutDetails
611
+ xml.tag! 'n2:NotifyURL', options[:notify_url] unless options[:notify_url].blank?
612
+
613
+ add_address(xml, 'n2:ShipToAddress', options[:shipping_address]) unless options[:shipping_address].blank?
614
+
615
+ add_payment_details_items_xml(xml, options, currency_code) unless options[:items].blank?
616
+
617
+ add_express_only_payment_details(xml, options) if options[:express_request]
618
+
619
+ # Any value other than Y – This is not a recurring transaction
620
+ # To pass Y in this field, you must have established a billing agreement with
621
+ # the buyer specifying the amount, frequency, and duration of the recurring payment.
622
+ # requires version 80.0 of the API
623
+ xml.tag! 'n2:Recurring', options[:recurring] unless options[:recurring].blank?
624
+ end
625
+ end
626
+
627
+ def add_button_source(xml)
628
+ button_source = (@options[:button_source] || application_id)
629
+ if !empty?(button_source)
630
+ xml.tag! 'n2:ButtonSource', button_source.to_s.slice(0, 32)
631
+ end
632
+ end
633
+
634
+ def add_express_only_payment_details(xml, options = {})
635
+ add_optional_fields(xml,
636
+ %w{n2:NoteText n2:PaymentAction
637
+ n2:TransactionId n2:AllowedPaymentMethod
638
+ n2:PaymentRequestID n2:SoftDescriptor },
639
+ options)
640
+ end
641
+
642
+ def add_optional_fields(xml, optional_fields, options = {})
643
+ optional_fields.each do |optional_text_field|
644
+ if optional_text_field =~ /(\w+:)(\w+)/
645
+ ns = $1
646
+ field = $2
647
+ field_as_symbol = field.underscore.to_sym
648
+ else
649
+ ns = ''
650
+ field = optional_text_field
651
+ field_as_symbol = optional_text_field.underscore.to_sym
652
+ end
653
+ xml.tag! ns + field, options[field_as_symbol] unless options[field_as_symbol].blank?
654
+ end
655
+ xml
656
+ end
657
+
658
+ def endpoint_url
659
+ URLS[test? ? :test : :live][@options[:signature].blank? ? :certificate : :signature]
660
+ end
661
+
662
+ def commit(action, request)
663
+ response = parse(action, ssl_post(endpoint_url, build_request(request), @options[:headers]))
664
+
665
+ build_response(successful?(response), message_from(response), response,
666
+ :test => test?,
667
+ :authorization => authorization_from(response),
668
+ :fraud_review => fraud_review?(response),
669
+ :error_code => standardized_error_code(response),
670
+ :avs_result => { :code => response[:avs_code] },
671
+ :cvv_result => response[:cvv2_code]
672
+ )
673
+ end
674
+
675
+ def standardized_error_code(response)
676
+ STANDARD_ERROR_CODE_MAPPING[error_codes(response).first]
677
+ end
678
+
679
+ def error_codes(response)
680
+ return [] unless response.has_key?(:error_codes)
681
+ response[:error_codes].split(',')
682
+ end
683
+
684
+ def fraud_review?(response)
685
+ response[:error_codes] == FRAUD_REVIEW_CODE
686
+ end
687
+
688
+ def authorization_from(response)
689
+ (
690
+ response[:transaction_id] ||
691
+ response[:authorization_id] ||
692
+ response[:refund_transaction_id] ||
693
+ response[:billing_agreement_id]
694
+ )
695
+ end
696
+
697
+ def successful?(response)
698
+ SUCCESS_CODES.include?(response[:ack])
699
+ end
700
+
701
+ def message_from(response)
702
+ response[:message] || response[:ack]
703
+ end
704
+
705
+ def date_to_iso(date)
706
+ (date.is_a?(Date) ? date.to_time : date).utc.iso8601
707
+ end
708
+
709
+ def item_amount(amount, currency_code)
710
+ if amount.to_i < 0 && non_fractional_currency?(currency_code)
711
+ amount(amount).to_f.floor
712
+ else
713
+ localized_amount(amount, currency_code)
714
+ end
715
+ end
716
+ end
717
+ end
718
+ end