tomriley-active_merchant 1.4.2.3

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 (278) hide show
  1. data/CHANGELOG +442 -0
  2. data/CONTRIBUTERS +102 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README +134 -0
  5. data/Rakefile +153 -0
  6. data/active_merchant.gemspec +15 -0
  7. data/gem-public_cert.pem +20 -0
  8. data/init.rb +4 -0
  9. data/lib/active_merchant/billing/avs_result.rb +98 -0
  10. data/lib/active_merchant/billing/base.rb +57 -0
  11. data/lib/active_merchant/billing/check.rb +68 -0
  12. data/lib/active_merchant/billing/credit_card.rb +159 -0
  13. data/lib/active_merchant/billing/credit_card_formatting.rb +21 -0
  14. data/lib/active_merchant/billing/credit_card_methods.rb +125 -0
  15. data/lib/active_merchant/billing/cvv_result.rb +38 -0
  16. data/lib/active_merchant/billing/expiry_date.rb +28 -0
  17. data/lib/active_merchant/billing/gateway.rb +158 -0
  18. data/lib/active_merchant/billing/gateways/authorize_net.rb +646 -0
  19. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +702 -0
  20. data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +233 -0
  21. data/lib/active_merchant/billing/gateways/beanstream.rb +102 -0
  22. data/lib/active_merchant/billing/gateways/beanstream_interac.rb +54 -0
  23. data/lib/active_merchant/billing/gateways/bogus.rb +98 -0
  24. data/lib/active_merchant/billing/gateways/braintree.rb +17 -0
  25. data/lib/active_merchant/billing/gateways/card_stream.rb +230 -0
  26. data/lib/active_merchant/billing/gateways/cyber_source.rb +406 -0
  27. data/lib/active_merchant/billing/gateways/data_cash.rb +595 -0
  28. data/lib/active_merchant/billing/gateways/efsnet.rb +229 -0
  29. data/lib/active_merchant/billing/gateways/eway.rb +272 -0
  30. data/lib/active_merchant/billing/gateways/exact.rb +222 -0
  31. data/lib/active_merchant/billing/gateways/instapay.rb +164 -0
  32. data/lib/active_merchant/billing/gateways/linkpoint.rb +396 -0
  33. data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +154 -0
  34. data/lib/active_merchant/billing/gateways/modern_payments.rb +36 -0
  35. data/lib/active_merchant/billing/gateways/modern_payments_cim.rb +214 -0
  36. data/lib/active_merchant/billing/gateways/moneris.rb +205 -0
  37. data/lib/active_merchant/billing/gateways/net_registry.rb +189 -0
  38. data/lib/active_merchant/billing/gateways/netbilling.rb +168 -0
  39. data/lib/active_merchant/billing/gateways/pay_junction.rb +392 -0
  40. data/lib/active_merchant/billing/gateways/pay_secure.rb +120 -0
  41. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +207 -0
  42. data/lib/active_merchant/billing/gateways/payflow/payflow_express_response.rb +39 -0
  43. data/lib/active_merchant/billing/gateways/payflow/payflow_response.rb +13 -0
  44. data/lib/active_merchant/billing/gateways/payflow.rb +236 -0
  45. data/lib/active_merchant/billing/gateways/payflow_express.rb +138 -0
  46. data/lib/active_merchant/billing/gateways/payflow_express_uk.rb +15 -0
  47. data/lib/active_merchant/billing/gateways/payflow_uk.rb +21 -0
  48. data/lib/active_merchant/billing/gateways/payment_express.rb +230 -0
  49. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +325 -0
  50. data/lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb +38 -0
  51. data/lib/active_merchant/billing/gateways/paypal.rb +108 -0
  52. data/lib/active_merchant/billing/gateways/paypal_ca.rb +13 -0
  53. data/lib/active_merchant/billing/gateways/paypal_express.rb +130 -0
  54. data/lib/active_merchant/billing/gateways/paypal_express_common.rb +20 -0
  55. data/lib/active_merchant/billing/gateways/plugnpay.rb +292 -0
  56. data/lib/active_merchant/billing/gateways/protx.rb +349 -0
  57. data/lib/active_merchant/billing/gateways/psigate.rb +214 -0
  58. data/lib/active_merchant/billing/gateways/psl_card.rb +306 -0
  59. data/lib/active_merchant/billing/gateways/quickpay.rb +213 -0
  60. data/lib/active_merchant/billing/gateways/realex.rb +200 -0
  61. data/lib/active_merchant/billing/gateways/sage/sage_bankcard.rb +88 -0
  62. data/lib/active_merchant/billing/gateways/sage/sage_core.rb +110 -0
  63. data/lib/active_merchant/billing/gateways/sage/sage_virtual_check.rb +97 -0
  64. data/lib/active_merchant/billing/gateways/sage.rb +146 -0
  65. data/lib/active_merchant/billing/gateways/secure_pay.rb +31 -0
  66. data/lib/active_merchant/billing/gateways/secure_pay_au.rb +157 -0
  67. data/lib/active_merchant/billing/gateways/secure_pay_tech.rb +113 -0
  68. data/lib/active_merchant/billing/gateways/skip_jack.rb +442 -0
  69. data/lib/active_merchant/billing/gateways/smart_ps.rb +254 -0
  70. data/lib/active_merchant/billing/gateways/trans_first.rb +127 -0
  71. data/lib/active_merchant/billing/gateways/transax.rb +26 -0
  72. data/lib/active_merchant/billing/gateways/trust_commerce.rb +418 -0
  73. data/lib/active_merchant/billing/gateways/usa_epay.rb +194 -0
  74. data/lib/active_merchant/billing/gateways/verifi.rb +228 -0
  75. data/lib/active_merchant/billing/gateways/viaklix.rb +165 -0
  76. data/lib/active_merchant/billing/gateways/wirecard.rb +318 -0
  77. data/lib/active_merchant/billing/gateways.rb +3 -0
  78. data/lib/active_merchant/billing/integrations/action_view_helper.rb +79 -0
  79. data/lib/active_merchant/billing/integrations/bogus/helper.rb +17 -0
  80. data/lib/active_merchant/billing/integrations/bogus/notification.rb +11 -0
  81. data/lib/active_merchant/billing/integrations/bogus/return.rb +10 -0
  82. data/lib/active_merchant/billing/integrations/bogus.rb +22 -0
  83. data/lib/active_merchant/billing/integrations/chronopay/helper.rb +81 -0
  84. data/lib/active_merchant/billing/integrations/chronopay/notification.rb +156 -0
  85. data/lib/active_merchant/billing/integrations/chronopay/return.rb +10 -0
  86. data/lib/active_merchant/billing/integrations/chronopay.rb +22 -0
  87. data/lib/active_merchant/billing/integrations/gestpay/common.rb +42 -0
  88. data/lib/active_merchant/billing/integrations/gestpay/helper.rb +70 -0
  89. data/lib/active_merchant/billing/integrations/gestpay/notification.rb +83 -0
  90. data/lib/active_merchant/billing/integrations/gestpay/return.rb +10 -0
  91. data/lib/active_merchant/billing/integrations/gestpay.rb +26 -0
  92. data/lib/active_merchant/billing/integrations/helper.rb +93 -0
  93. data/lib/active_merchant/billing/integrations/hi_trust/helper.rb +58 -0
  94. data/lib/active_merchant/billing/integrations/hi_trust/notification.rb +59 -0
  95. data/lib/active_merchant/billing/integrations/hi_trust/return.rb +67 -0
  96. data/lib/active_merchant/billing/integrations/hi_trust.rb +26 -0
  97. data/lib/active_merchant/billing/integrations/nochex/helper.rb +68 -0
  98. data/lib/active_merchant/billing/integrations/nochex/notification.rb +94 -0
  99. data/lib/active_merchant/billing/integrations/nochex/return.rb +10 -0
  100. data/lib/active_merchant/billing/integrations/nochex.rb +87 -0
  101. data/lib/active_merchant/billing/integrations/notification.rb +62 -0
  102. data/lib/active_merchant/billing/integrations/paypal/helper.rb +118 -0
  103. data/lib/active_merchant/billing/integrations/paypal/notification.rb +154 -0
  104. data/lib/active_merchant/billing/integrations/paypal/return.rb +10 -0
  105. data/lib/active_merchant/billing/integrations/paypal.rb +40 -0
  106. data/lib/active_merchant/billing/integrations/quickpay/helper.rb +72 -0
  107. data/lib/active_merchant/billing/integrations/quickpay/notification.rb +74 -0
  108. data/lib/active_merchant/billing/integrations/quickpay.rb +18 -0
  109. data/lib/active_merchant/billing/integrations/return.rb +35 -0
  110. data/lib/active_merchant/billing/integrations/two_checkout/helper.rb +59 -0
  111. data/lib/active_merchant/billing/integrations/two_checkout/notification.rb +114 -0
  112. data/lib/active_merchant/billing/integrations/two_checkout/return.rb +17 -0
  113. data/lib/active_merchant/billing/integrations/two_checkout.rb +23 -0
  114. data/lib/active_merchant/billing/integrations.rb +22 -0
  115. data/lib/active_merchant/billing/response.rb +32 -0
  116. data/lib/active_merchant/lib/connection.rb +170 -0
  117. data/lib/active_merchant/lib/country.rb +319 -0
  118. data/lib/active_merchant/lib/error.rb +4 -0
  119. data/lib/active_merchant/lib/post_data.rb +22 -0
  120. data/lib/active_merchant/lib/posts_data.rb +47 -0
  121. data/lib/active_merchant/lib/requires_parameters.rb +16 -0
  122. data/lib/active_merchant/lib/utils.rb +18 -0
  123. data/lib/active_merchant/lib/validateable.rb +76 -0
  124. data/lib/active_merchant.rb +60 -0
  125. data/lib/certs/cacert.pem +7815 -0
  126. data/lib/support/gateway_support.rb +58 -0
  127. data/script/destroy +14 -0
  128. data/script/generate +14 -0
  129. data/test/fixtures.yml +330 -0
  130. data/test/remote/gateways/remote_authorize_net_cim_test.rb +459 -0
  131. data/test/remote/gateways/remote_authorize_net_test.rb +145 -0
  132. data/test/remote/gateways/remote_beanstream_interac_test.rb +53 -0
  133. data/test/remote/gateways/remote_beanstream_test.rb +150 -0
  134. data/test/remote/gateways/remote_braintree_test.rb +154 -0
  135. data/test/remote/gateways/remote_card_stream_test.rb +148 -0
  136. data/test/remote/gateways/remote_cyber_source_test.rb +144 -0
  137. data/test/remote/gateways/remote_data_cash_test.rb +357 -0
  138. data/test/remote/gateways/remote_efsnet_test.rb +81 -0
  139. data/test/remote/gateways/remote_eway_test.rb +74 -0
  140. data/test/remote/gateways/remote_exact_test.rb +60 -0
  141. data/test/remote/gateways/remote_instapay_test.rb +61 -0
  142. data/test/remote/gateways/remote_linkpoint_test.rb +112 -0
  143. data/test/remote/gateways/remote_merchant_e_solutions_test.rb +173 -0
  144. data/test/remote/gateways/remote_modern_payments_cim_test.rb +58 -0
  145. data/test/remote/gateways/remote_modern_payments_test.rb +43 -0
  146. data/test/remote/gateways/remote_moneris_test.rb +82 -0
  147. data/test/remote/gateways/remote_net_registry_test.rb +85 -0
  148. data/test/remote/gateways/remote_netbilling_test.rb +70 -0
  149. data/test/remote/gateways/remote_pay_junction_test.rb +143 -0
  150. data/test/remote/gateways/remote_pay_secure_test.rb +39 -0
  151. data/test/remote/gateways/remote_payflow_express_test.rb +50 -0
  152. data/test/remote/gateways/remote_payflow_test.rb +237 -0
  153. data/test/remote/gateways/remote_payflow_uk_test.rb +173 -0
  154. data/test/remote/gateways/remote_payment_express_test.rb +136 -0
  155. data/test/remote/gateways/remote_paypal_express_test.rb +49 -0
  156. data/test/remote/gateways/remote_paypal_test.rb +167 -0
  157. data/test/remote/gateways/remote_plugnpay_test.rb +72 -0
  158. data/test/remote/gateways/remote_protx_test.rb +219 -0
  159. data/test/remote/gateways/remote_psigate_test.rb +50 -0
  160. data/test/remote/gateways/remote_psl_card_test.rb +125 -0
  161. data/test/remote/gateways/remote_quickpay_test.rb +190 -0
  162. data/test/remote/gateways/remote_realex_test.rb +224 -0
  163. data/test/remote/gateways/remote_sage_bankcard_test.rb +109 -0
  164. data/test/remote/gateways/remote_sage_test.rb +87 -0
  165. data/test/remote/gateways/remote_sage_virtual_check_test.rb +62 -0
  166. data/test/remote/gateways/remote_secure_pay_au_test.rb +40 -0
  167. data/test/remote/gateways/remote_secure_pay_tech_test.rb +37 -0
  168. data/test/remote/gateways/remote_secure_pay_test.rb +28 -0
  169. data/test/remote/gateways/remote_skipjack_test.rb +105 -0
  170. data/test/remote/gateways/remote_trans_first_test.rb +34 -0
  171. data/test/remote/gateways/remote_transax_test.rb +112 -0
  172. data/test/remote/gateways/remote_trust_commerce_test.rb +152 -0
  173. data/test/remote/gateways/remote_usa_epay_test.rb +46 -0
  174. data/test/remote/gateways/remote_verifi_test.rb +107 -0
  175. data/test/remote/gateways/remote_viaklix_test.rb +43 -0
  176. data/test/remote/gateways/remote_wirecard_test.rb +111 -0
  177. data/test/remote/integrations/remote_gestpay_integration_test.rb +37 -0
  178. data/test/remote/integrations/remote_paypal_integration_test.rb +26 -0
  179. data/test/test_helper.rb +182 -0
  180. data/test/unit/avs_result_test.rb +59 -0
  181. data/test/unit/base_test.rb +55 -0
  182. data/test/unit/check_test.rb +88 -0
  183. data/test/unit/connection_test.rb +129 -0
  184. data/test/unit/country_code_test.rb +33 -0
  185. data/test/unit/country_test.rb +64 -0
  186. data/test/unit/credit_card_formatting_test.rb +19 -0
  187. data/test/unit/credit_card_methods_test.rb +170 -0
  188. data/test/unit/credit_card_test.rb +318 -0
  189. data/test/unit/cvv_result_test.rb +33 -0
  190. data/test/unit/expiry_date_test.rb +21 -0
  191. data/test/unit/gateways/authorize_net_cim_test.rb +638 -0
  192. data/test/unit/gateways/authorize_net_test.rb +290 -0
  193. data/test/unit/gateways/beanstream_interac_test.rb +51 -0
  194. data/test/unit/gateways/beanstream_test.rb +108 -0
  195. data/test/unit/gateways/bogus_test.rb +46 -0
  196. data/test/unit/gateways/braintree_test.rb +126 -0
  197. data/test/unit/gateways/card_stream_test.rb +90 -0
  198. data/test/unit/gateways/cyber_source_test.rb +188 -0
  199. data/test/unit/gateways/data_cash_test.rb +133 -0
  200. data/test/unit/gateways/efsnet_test.rb +123 -0
  201. data/test/unit/gateways/eway_test.rb +118 -0
  202. data/test/unit/gateways/exact_test.rb +156 -0
  203. data/test/unit/gateways/gateway_test.rb +48 -0
  204. data/test/unit/gateways/instapay_test.rb +102 -0
  205. data/test/unit/gateways/linkpoint_test.rb +167 -0
  206. data/test/unit/gateways/merchant_e_solutions_test.rb +169 -0
  207. data/test/unit/gateways/modern_payments_cim_test.rb +171 -0
  208. data/test/unit/gateways/moneris_test.rb +158 -0
  209. data/test/unit/gateways/net_registry_test.rb +416 -0
  210. data/test/unit/gateways/netbilling_test.rb +54 -0
  211. data/test/unit/gateways/pay_junction_test.rb +123 -0
  212. data/test/unit/gateways/pay_secure_test.rb +71 -0
  213. data/test/unit/gateways/payflow_express_test.rb +173 -0
  214. data/test/unit/gateways/payflow_express_uk_test.rb +86 -0
  215. data/test/unit/gateways/payflow_test.rb +305 -0
  216. data/test/unit/gateways/payflow_uk_test.rb +30 -0
  217. data/test/unit/gateways/payment_express_test.rb +195 -0
  218. data/test/unit/gateways/paypal_express_test.rb +382 -0
  219. data/test/unit/gateways/paypal_test.rb +520 -0
  220. data/test/unit/gateways/plugnpay_test.rb +86 -0
  221. data/test/unit/gateways/protx_test.rb +139 -0
  222. data/test/unit/gateways/psigate_test.rb +169 -0
  223. data/test/unit/gateways/psl_card_test.rb +64 -0
  224. data/test/unit/gateways/quickpay_test.rb +112 -0
  225. data/test/unit/gateways/realex_test.rb +151 -0
  226. data/test/unit/gateways/sage_bankcard_test.rb +162 -0
  227. data/test/unit/gateways/sage_virtual_check_test.rb +71 -0
  228. data/test/unit/gateways/secure_pay_au_test.rb +207 -0
  229. data/test/unit/gateways/secure_pay_tech_test.rb +44 -0
  230. data/test/unit/gateways/secure_pay_test.rb +87 -0
  231. data/test/unit/gateways/skip_jack_test.rb +133 -0
  232. data/test/unit/gateways/trans_first_test.rb +112 -0
  233. data/test/unit/gateways/trust_commerce_test.rb +90 -0
  234. data/test/unit/gateways/usa_epay_test.rb +128 -0
  235. data/test/unit/gateways/verifi_test.rb +96 -0
  236. data/test/unit/gateways/viaklix_test.rb +78 -0
  237. data/test/unit/gateways/wirecard_test.rb +250 -0
  238. data/test/unit/generators/test_gateway_generator.rb +46 -0
  239. data/test/unit/generators/test_generator_helper.rb +20 -0
  240. data/test/unit/generators/test_integration_generator.rb +53 -0
  241. data/test/unit/integrations/action_view_helper_test.rb +50 -0
  242. data/test/unit/integrations/bogus_module_test.rb +20 -0
  243. data/test/unit/integrations/chronopay_module_test.rb +13 -0
  244. data/test/unit/integrations/gestpay_module_test.rb +14 -0
  245. data/test/unit/integrations/helpers/bogus_helper_test.rb +28 -0
  246. data/test/unit/integrations/helpers/chronopay_helper_test.rb +67 -0
  247. data/test/unit/integrations/helpers/gestpay_helper_test.rb +100 -0
  248. data/test/unit/integrations/helpers/hi_trust_helper_test.rb +16 -0
  249. data/test/unit/integrations/helpers/nochex_helper_test.rb +53 -0
  250. data/test/unit/integrations/helpers/paypal_helper_test.rb +162 -0
  251. data/test/unit/integrations/helpers/quickpay_helper_test.rb +40 -0
  252. data/test/unit/integrations/helpers/two_checkout_helper_test.rb +92 -0
  253. data/test/unit/integrations/hi_trust_module_test.rb +13 -0
  254. data/test/unit/integrations/nochex_module_test.rb +13 -0
  255. data/test/unit/integrations/notifications/chronopay_notification_test.rb +66 -0
  256. data/test/unit/integrations/notifications/gestpay_notification_test.rb +60 -0
  257. data/test/unit/integrations/notifications/hi_trust_notification_test.rb +59 -0
  258. data/test/unit/integrations/notifications/nochex_notification_test.rb +51 -0
  259. data/test/unit/integrations/notifications/notification_test.rb +54 -0
  260. data/test/unit/integrations/notifications/paypal_notification_test.rb +85 -0
  261. data/test/unit/integrations/notifications/quickpay_notification_test.rb +69 -0
  262. data/test/unit/integrations/notifications/two_checkout_notification_test.rb +55 -0
  263. data/test/unit/integrations/paypal_module_test.rb +28 -0
  264. data/test/unit/integrations/quickpay_module_test.rb +9 -0
  265. data/test/unit/integrations/returns/chronopay_return_test.rb +11 -0
  266. data/test/unit/integrations/returns/gestpay_return_test.rb +10 -0
  267. data/test/unit/integrations/returns/hi_trust_return_test.rb +24 -0
  268. data/test/unit/integrations/returns/nochex_return_test.rb +10 -0
  269. data/test/unit/integrations/returns/paypal_return_test.rb +10 -0
  270. data/test/unit/integrations/returns/return_test.rb +11 -0
  271. data/test/unit/integrations/returns/two_checkout_return_test.rb +24 -0
  272. data/test/unit/integrations/two_checkout_module_test.rb +13 -0
  273. data/test/unit/post_data_test.rb +55 -0
  274. data/test/unit/posts_data_test.rb +48 -0
  275. data/test/unit/response_test.rb +28 -0
  276. data/test/unit/utils_test.rb +7 -0
  277. data/test/unit/validateable_test.rb +60 -0
  278. metadata +364 -0
@@ -0,0 +1,230 @@
1
+ require 'rexml/document'
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+
6
+ # In NZ DPS supports ANZ, Westpac, National Bank, ASB and BNZ.
7
+ # In Australia DPS supports ANZ, NAB, Westpac, CBA, St George and Bank of South Australia.
8
+ # The Maybank in Malaysia is supported and the Citibank for Singapore.
9
+ class PaymentExpressGateway < Gateway
10
+ self.default_currency = 'NZD'
11
+ # PS supports all major credit cards; Visa, Mastercard, Amex, Diners, BankCard & JCB.
12
+ # Various white label cards can be accepted as well; Farmers, AirNZCard and Elders etc.
13
+ # Please note that not all acquirers and Eftpos networks can support some of these card types.
14
+ # VISA, Mastercard, Diners Club and Farmers cards are supported
15
+ #
16
+ # However, regular accounts with DPS only support VISA and Mastercard
17
+ self.supported_cardtypes = [ :visa, :master, :american_express, :diners_club, :jcb ]
18
+
19
+ self.supported_countries = [ 'AU', 'MY', 'NZ', 'SG', 'ZA', 'GB', 'US' ]
20
+
21
+ self.homepage_url = 'http://www.paymentexpress.com/'
22
+ self.display_name = 'PaymentExpress'
23
+
24
+ URL = 'https://www.paymentexpress.com/pxpost.aspx'
25
+
26
+ APPROVED = '1'
27
+
28
+ TRANSACTIONS = {
29
+ :purchase => 'Purchase',
30
+ :credit => 'Refund',
31
+ :authorization => 'Auth',
32
+ :capture => 'Complete',
33
+ :validate => 'Validate'
34
+ }
35
+
36
+ # We require the DPS gateway username and password when the object is created.
37
+ def initialize(options = {})
38
+ # A DPS username and password must exist
39
+ requires!(options, :login, :password)
40
+ # Make the options an instance variable
41
+ @options = options
42
+ super
43
+ end
44
+
45
+ # Funds are transferred immediately.
46
+ def purchase(money, payment_source, options = {})
47
+ request = build_purchase_or_authorization_request(money, payment_source, options)
48
+ commit(:purchase, request)
49
+ end
50
+
51
+ # NOTE: Perhaps in options we allow a transaction note to be inserted
52
+ # Verifies that funds are available for the requested card and amount and reserves the specified amount.
53
+ # See: http://www.paymentexpress.com/technical_resources/ecommerce_nonhosted/pxpost.html#Authcomplete
54
+ def authorize(money, payment_source, options = {})
55
+ request = build_purchase_or_authorization_request(money, payment_source, options)
56
+ commit(:authorization, request)
57
+ end
58
+
59
+ # Transfer pre-authorized funds immediately
60
+ # See: http://www.paymentexpress.com/technical_resources/ecommerce_nonhosted/pxpost.html#Authcomplete
61
+ def capture(money, identification, options = {})
62
+ request = build_capture_or_credit_request(money, identification, options)
63
+ commit(:capture, request)
64
+ end
65
+
66
+ # Refund funds to the card holder
67
+ def credit(money, identification, options = {})
68
+ requires!(options, :description)
69
+
70
+ request = build_capture_or_credit_request(money, identification, options)
71
+ commit(:credit, request)
72
+ end
73
+
74
+ # token based billing
75
+
76
+ # initiates a "Validate" transcation to store card data on payment express servers
77
+ # returns a "token" that can be used to rebill this card
78
+ # see: http://www.paymentexpress.com/technical_resources/ecommerce_nonhosted/pxpost.html#Tokenbilling
79
+ # PaymentExpress does not support unstoring a stored card.
80
+ def store(credit_card, options = {})
81
+ request = build_token_request(credit_card, options)
82
+ commit(:validate, request)
83
+ end
84
+
85
+ private
86
+
87
+ def build_purchase_or_authorization_request(money, payment_source, options)
88
+ result = new_transaction
89
+
90
+ if payment_source.is_a?(String)
91
+ add_billing_token(result, payment_source)
92
+ else
93
+ add_credit_card(result, payment_source)
94
+ end
95
+
96
+ add_amount(result, money, options)
97
+ add_invoice(result, options)
98
+ add_address_verification_data(result, options)
99
+ result
100
+ end
101
+
102
+ def build_capture_or_credit_request(money, identification, options)
103
+ result = new_transaction
104
+
105
+ add_amount(result, money, options)
106
+ add_invoice(result, options)
107
+ add_reference(result, identification)
108
+ result
109
+ end
110
+
111
+ def build_token_request(credit_card, options)
112
+ result = new_transaction
113
+ add_credit_card(result, credit_card)
114
+ add_amount(result, 100, options) #need to make an auth request for $1
115
+ add_token_request(result, options)
116
+ result
117
+ end
118
+
119
+ def add_credentials(xml)
120
+ xml.add_element("PostUsername").text = @options[:login]
121
+ xml.add_element("PostPassword").text = @options[:password]
122
+ end
123
+
124
+ def add_reference(xml, identification)
125
+ xml.add_element("DpsTxnRef").text = identification
126
+ end
127
+
128
+ def add_credit_card(xml, credit_card)
129
+ xml.add_element("CardHolderName").text = credit_card.name
130
+ xml.add_element("CardNumber").text = credit_card.number
131
+ xml.add_element("DateExpiry").text = format_date(credit_card.month, credit_card.year)
132
+
133
+ if credit_card.verification_value?
134
+ xml.add_element("Cvc2").text = credit_card.verification_value
135
+ end
136
+
137
+ if requires_start_date_or_issue_number?(credit_card)
138
+ xml.add_element("DateStart").text = format_date(credit_card.start_month, credit_card.start_year) unless credit_card.start_month.blank? || credit_card.start_year.blank?
139
+ xml.add_element("IssueNumber").text = credit_card.issue_number unless credit_card.issue_number.blank?
140
+ end
141
+ end
142
+
143
+ def add_billing_token(xml, token)
144
+ xml.add_element("DpsBillingId").text = token
145
+ end
146
+
147
+ def add_token_request(xml, options)
148
+ xml.add_element("BillingId").text = options[:billing_id] if options[:billing_id]
149
+ xml.add_element("EnableAddBillCard").text = 1
150
+ end
151
+
152
+ def add_amount(xml, money, options)
153
+ xml.add_element("Amount").text = amount(money)
154
+ xml.add_element("InputCurrency").text = options[:currency] || currency(money)
155
+ end
156
+
157
+ def add_transaction_type(xml, action)
158
+ xml.add_element("TxnType").text = TRANSACTIONS[action]
159
+ end
160
+
161
+ def add_invoice(xml, options)
162
+ xml.add_element("TxnId").text = options[:order_id].to_s.slice(0, 16) unless options[:order_id].blank?
163
+ xml.add_element("MerchantReference").text = options[:description] unless options[:description].blank?
164
+ end
165
+
166
+ def add_address_verification_data(xml, options)
167
+ address = options[:billing_address] || options[:address]
168
+ return if address.nil?
169
+
170
+ xml.add_element("EnableAvsData").text = 1
171
+ xml.add_element("AvsAction").text = 1
172
+
173
+ xml.add_element("AvsStreetAddress").text = address[:address1]
174
+ xml.add_element("AvsPostCode").text = address[:zip]
175
+ end
176
+
177
+ def new_transaction
178
+ REXML::Document.new.add_element("Txn")
179
+ end
180
+
181
+ # Take in the request and post it to DPS
182
+ def commit(action, request)
183
+ add_credentials(request)
184
+ add_transaction_type(request, action)
185
+
186
+ # Parse the XML response
187
+ response = parse( ssl_post(URL, request.to_s) )
188
+
189
+ # Return a response
190
+ PaymentExpressResponse.new(response[:success] == APPROVED, response[:response_text], response,
191
+ :test => response[:test_mode] == '1',
192
+ :authorization => response[:dps_txn_ref]
193
+ )
194
+ end
195
+
196
+ # Response XML documentation: http://www.paymentexpress.com/technical_resources/ecommerce_nonhosted/pxpost.html#XMLTxnOutput
197
+ def parse(xml_string)
198
+ response = {}
199
+
200
+ xml = REXML::Document.new(xml_string)
201
+
202
+ # Gather all root elements such as HelpText
203
+ xml.elements.each('Txn/*') do |element|
204
+ response[element.name.underscore.to_sym] = element.text unless element.name == 'Transaction'
205
+ end
206
+
207
+ # Gather all transaction elements and prefix with "account_"
208
+ # So we could access the MerchantResponseText by going
209
+ # response[account_merchant_response_text]
210
+ xml.elements.each('Txn/Transaction/*') do |element|
211
+ response[element.name.underscore.to_sym] = element.text
212
+ end
213
+
214
+ response
215
+ end
216
+
217
+ def format_date(month, year)
218
+ "#{format(month, :two_digits)}#{format(year, :two_digits)}"
219
+ end
220
+ end
221
+
222
+ class PaymentExpressResponse < Response
223
+ # add a method to response so we can easily get the token
224
+ # for Validate transactions
225
+ def token
226
+ @params["billing_id"] || @params["dps_billing_id"]
227
+ end
228
+ end
229
+ end
230
+ end
@@ -0,0 +1,325 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ # This module is included in both PaypalGateway and PaypalExpressGateway
4
+ module PaypalCommonAPI
5
+ def self.included(base)
6
+ base.default_currency = 'USD'
7
+ base.cattr_accessor :pem_file
8
+ base.cattr_accessor :signature
9
+ end
10
+
11
+ API_VERSION = '52.0'
12
+
13
+ URLS = {
14
+ :test => { :certificate => 'https://api.sandbox.paypal.com/2.0/',
15
+ :signature => 'https://api-3t.sandbox.paypal.com/2.0/' },
16
+ :live => { :certificate => 'https://api-aa.paypal.com/2.0/',
17
+ :signature => 'https://api-3t.paypal.com/2.0/' }
18
+ }
19
+
20
+ PAYPAL_NAMESPACE = 'urn:ebay:api:PayPalAPI'
21
+ EBAY_NAMESPACE = 'urn:ebay:apis:eBLBaseComponents'
22
+
23
+ ENVELOPE_NAMESPACES = { 'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema',
24
+ 'xmlns:env' => 'http://schemas.xmlsoap.org/soap/envelope/',
25
+ 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance'
26
+ }
27
+ CREDENTIALS_NAMESPACES = { 'xmlns' => PAYPAL_NAMESPACE,
28
+ 'xmlns:n1' => EBAY_NAMESPACE,
29
+ 'env:mustUnderstand' => '0'
30
+ }
31
+
32
+ AUSTRALIAN_STATES = {
33
+ 'ACT' => 'Australian Capital Territory',
34
+ 'NSW' => 'New South Wales',
35
+ 'NT' => 'Northern Territory',
36
+ 'QLD' => 'Queensland',
37
+ 'SA' => 'South Australia',
38
+ 'TAS' => 'Tasmania',
39
+ 'VIC' => 'Victoria',
40
+ 'WA' => 'Western Australia'
41
+ }
42
+
43
+ SUCCESS_CODES = [ 'Success', 'SuccessWithWarning' ]
44
+
45
+ FRAUD_REVIEW_CODE = "11610"
46
+
47
+ # The gateway must be configured with either your PayPal PEM file
48
+ # or your PayPal API Signature. Only one is required.
49
+ #
50
+ # <tt>:pem</tt> The text of your PayPal PEM file. Note
51
+ # this is not the path to file, but its
52
+ # contents. If you are only using one PEM
53
+ # file on your site you can declare it
54
+ # globally and then you won't need to
55
+ # include this option
56
+ #
57
+ # <tt>:signature</tt> The text of your PayPal signature.
58
+ # If you are only using one API Signature
59
+ # on your site you can declare it
60
+ # globally and then you won't need to
61
+ # include this option
62
+
63
+ def initialize(options = {})
64
+ requires!(options, :login, :password)
65
+
66
+ @options = {
67
+ :pem => pem_file,
68
+ :signature => signature
69
+ }.update(options)
70
+
71
+ if @options[:pem].blank? && @options[:signature].blank?
72
+ raise ArgumentError, "An API Certificate or API Signature is required to make requests to PayPal"
73
+ end
74
+
75
+ super
76
+ end
77
+
78
+ def test?
79
+ @options[:test] || Base.gateway_mode == :test
80
+ end
81
+
82
+ def reauthorize(money, authorization, options = {})
83
+ commit 'DoReauthorization', build_reauthorize_request(money, authorization, options)
84
+ end
85
+
86
+ def capture(money, authorization, options = {})
87
+ commit 'DoCapture', build_capture_request(money, authorization, options)
88
+ end
89
+
90
+ # Transfer money to one or more recipients.
91
+ #
92
+ # gateway.transfer 1000, 'bob@example.com',
93
+ # :subject => "The money I owe you", :note => "Sorry it's so late"
94
+ #
95
+ # gateway.transfer [1000, 'fred@example.com'],
96
+ # [2450, 'wilma@example.com', :note => 'You will receive another payment on 3/24'],
97
+ # [2000, 'barney@example.com'],
98
+ # :subject => "Your Earnings", :note => "Thanks for your business."
99
+ #
100
+ def transfer(*args)
101
+ commit 'MassPay', build_mass_pay_request(*args)
102
+ end
103
+
104
+ def void(authorization, options = {})
105
+ commit 'DoVoid', build_void_request(authorization, options)
106
+ end
107
+
108
+ def credit(money, identification, options = {})
109
+ commit 'RefundTransaction', build_credit_request(money, identification, options)
110
+ end
111
+
112
+ private
113
+ def build_reauthorize_request(money, authorization, options)
114
+ xml = Builder::XmlMarkup.new
115
+
116
+ xml.tag! 'DoReauthorizationReq', 'xmlns' => PAYPAL_NAMESPACE do
117
+ xml.tag! 'DoReauthorizationRequest', 'xmlns:n2' => EBAY_NAMESPACE do
118
+ xml.tag! 'n2:Version', API_VERSION
119
+ xml.tag! 'AuthorizationID', authorization
120
+ xml.tag! 'Amount', amount(money), 'currencyID' => options[:currency] || currency(money)
121
+ end
122
+ end
123
+
124
+ xml.target!
125
+ end
126
+
127
+ def build_capture_request(money, authorization, options)
128
+ xml = Builder::XmlMarkup.new
129
+
130
+ xml.tag! 'DoCaptureReq', 'xmlns' => PAYPAL_NAMESPACE do
131
+ xml.tag! 'DoCaptureRequest', 'xmlns:n2' => EBAY_NAMESPACE do
132
+ xml.tag! 'n2:Version', API_VERSION
133
+ xml.tag! 'AuthorizationID', authorization
134
+ xml.tag! 'Amount', amount(money), 'currencyID' => options[:currency] || currency(money)
135
+ xml.tag! 'CompleteType', 'Complete'
136
+ xml.tag! 'Note', options[:description]
137
+ end
138
+ end
139
+
140
+ xml.target!
141
+ end
142
+
143
+ def build_credit_request(money, identification, options)
144
+ xml = Builder::XmlMarkup.new
145
+
146
+ xml.tag! 'RefundTransactionReq', 'xmlns' => PAYPAL_NAMESPACE do
147
+ xml.tag! 'RefundTransactionRequest', 'xmlns:n2' => EBAY_NAMESPACE do
148
+ xml.tag! 'n2:Version', API_VERSION
149
+ xml.tag! 'TransactionID', identification
150
+ xml.tag! 'Amount', amount(money), 'currencyID' => options[:currency] || currency(money)
151
+ xml.tag! 'RefundType', 'Partial'
152
+ xml.tag! 'Memo', options[:note] unless options[:note].blank?
153
+ end
154
+ end
155
+
156
+ xml.target!
157
+ end
158
+
159
+ def build_void_request(authorization, options)
160
+ xml = Builder::XmlMarkup.new
161
+
162
+ xml.tag! 'DoVoidReq', 'xmlns' => PAYPAL_NAMESPACE do
163
+ xml.tag! 'DoVoidRequest', 'xmlns:n2' => EBAY_NAMESPACE do
164
+ xml.tag! 'n2:Version', API_VERSION
165
+ xml.tag! 'AuthorizationID', authorization
166
+ xml.tag! 'Note', options[:description]
167
+ end
168
+ end
169
+
170
+ xml.target!
171
+ end
172
+
173
+ def build_mass_pay_request(*args)
174
+ default_options = args.last.is_a?(Hash) ? args.pop : {}
175
+ recipients = args.first.is_a?(Array) ? args : [args]
176
+
177
+ xml = Builder::XmlMarkup.new
178
+
179
+ xml.tag! 'MassPayReq', 'xmlns' => PAYPAL_NAMESPACE do
180
+ xml.tag! 'MassPayRequest', 'xmlns:n2' => EBAY_NAMESPACE do
181
+ xml.tag! 'n2:Version', API_VERSION
182
+ xml.tag! 'EmailSubject', default_options[:subject] if default_options[:subject]
183
+ recipients.each do |money, recipient, options|
184
+ options ||= default_options
185
+ xml.tag! 'MassPayItem' do
186
+ xml.tag! 'ReceiverEmail', recipient
187
+ xml.tag! 'Amount', amount(money), 'currencyID' => options[:currency] || currency(money)
188
+ xml.tag! 'Note', options[:note] if options[:note]
189
+ xml.tag! 'UniqueId', options[:unique_id] if options[:unique_id]
190
+ end
191
+ end
192
+ end
193
+ end
194
+
195
+ xml.target!
196
+ end
197
+
198
+ def parse(action, xml)
199
+ response = {}
200
+
201
+ error_messages = []
202
+ error_codes = []
203
+
204
+ xml = REXML::Document.new(xml)
205
+ if root = REXML::XPath.first(xml, "//#{action}Response")
206
+ root.elements.each do |node|
207
+ case node.name
208
+ when 'Errors'
209
+ short_message = nil
210
+ long_message = nil
211
+
212
+ node.elements.each do |child|
213
+ case child.name
214
+ when "LongMessage"
215
+ long_message = child.text unless child.text.blank?
216
+ when "ShortMessage"
217
+ short_message = child.text unless child.text.blank?
218
+ when "ErrorCode"
219
+ error_codes << child.text unless child.text.blank?
220
+ end
221
+ end
222
+
223
+ if message = long_message || short_message
224
+ error_messages << message
225
+ end
226
+ else
227
+ parse_element(response, node)
228
+ end
229
+ end
230
+ response[:message] = error_messages.uniq.join(". ") unless error_messages.empty?
231
+ response[:error_codes] = error_codes.uniq.join(",") unless error_codes.empty?
232
+ elsif root = REXML::XPath.first(xml, "//SOAP-ENV:Fault")
233
+ parse_element(response, root)
234
+ response[:message] = "#{response[:faultcode]}: #{response[:faultstring]} - #{response[:detail]}"
235
+ end
236
+
237
+ response
238
+ end
239
+
240
+ def parse_element(response, node)
241
+ if node.has_elements?
242
+ node.elements.each{|e| parse_element(response, e) }
243
+ else
244
+ response[node.name.underscore.to_sym] = node.text
245
+ node.attributes.each do |k, v|
246
+ response["#{node.name.underscore}_#{k.underscore}".to_sym] = v if k == 'currencyID'
247
+ end
248
+ end
249
+ end
250
+
251
+ def build_request(body)
252
+ xml = Builder::XmlMarkup.new
253
+
254
+ xml.instruct!
255
+ xml.tag! 'env:Envelope', ENVELOPE_NAMESPACES do
256
+ xml.tag! 'env:Header' do
257
+ add_credentials(xml)
258
+ end
259
+
260
+ xml.tag! 'env:Body' do
261
+ xml << body
262
+ end
263
+ end
264
+ xml.target!
265
+ end
266
+
267
+ def add_credentials(xml)
268
+ xml.tag! 'RequesterCredentials', CREDENTIALS_NAMESPACES do
269
+ xml.tag! 'n1:Credentials' do
270
+ xml.tag! 'Username', @options[:login]
271
+ xml.tag! 'Password', @options[:password]
272
+ xml.tag! 'Subject', @options[:subject]
273
+ xml.tag! 'Signature', @options[:signature] unless @options[:signature].blank?
274
+ end
275
+ end
276
+ end
277
+
278
+ def add_address(xml, element, address)
279
+ return if address.nil?
280
+ xml.tag! element do
281
+ xml.tag! 'n2:Name', address[:name]
282
+ xml.tag! 'n2:Street1', address[:address1]
283
+ xml.tag! 'n2:Street2', address[:address2]
284
+ xml.tag! 'n2:CityName', address[:city]
285
+ xml.tag! 'n2:StateOrProvince', address[:state].blank? ? 'N/A' : address[:state]
286
+ xml.tag! 'n2:Country', address[:country]
287
+ xml.tag! 'n2:PostalCode', address[:zip]
288
+ xml.tag! 'n2:Phone', address[:phone]
289
+ end
290
+ end
291
+
292
+ def endpoint_url
293
+ URLS[test? ? :test : :live][@options[:signature].blank? ? :certificate : :signature]
294
+ end
295
+
296
+ def commit(action, request)
297
+ response = parse(action, ssl_post(endpoint_url, build_request(request)))
298
+
299
+ build_response(successful?(response), message_from(response), response,
300
+ :test => test?,
301
+ :authorization => authorization_from(response),
302
+ :fraud_review => fraud_review?(response),
303
+ :avs_result => { :code => response[:avs_code] },
304
+ :cvv_result => response[:cvv2_code]
305
+ )
306
+ end
307
+
308
+ def fraud_review?(response)
309
+ response[:error_codes] == FRAUD_REVIEW_CODE
310
+ end
311
+
312
+ def authorization_from(response)
313
+ response[:transaction_id] || response[:authorization_id] || response[:refund_transaction_id] # middle one is from reauthorization
314
+ end
315
+
316
+ def successful?(response)
317
+ SUCCESS_CODES.include?(response[:ack])
318
+ end
319
+
320
+ def message_from(response)
321
+ response[:message] || response[:ack]
322
+ end
323
+ end
324
+ end
325
+ end
@@ -0,0 +1,38 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ class PaypalExpressResponse < Response
4
+ def email
5
+ @params['payer']
6
+ end
7
+
8
+ def name
9
+ [@params['first_name'], @params['middle_name'], @params['last_name']].compact.join(' ')
10
+ end
11
+
12
+ def token
13
+ @params['token']
14
+ end
15
+
16
+ def payer_id
17
+ @params['payer_id']
18
+ end
19
+
20
+ def payer_country
21
+ @params['payer_country']
22
+ end
23
+
24
+ def address
25
+ { 'name' => @params['name'],
26
+ 'company' => @params['payer_business'],
27
+ 'address1' => @params['street1'],
28
+ 'address2' => @params['street2'],
29
+ 'city' => @params['city_name'],
30
+ 'state' => @params['state_or_province'],
31
+ 'country' => @params['country'],
32
+ 'zip' => @params['postal_code'],
33
+ 'phone' => nil
34
+ }
35
+ end
36
+ end
37
+ end
38
+ end