Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'master' of https://github.com/Shopify/active_merchant

* 'master' of https://github.com/Shopify/active_merchant: (300 commits)
  Packaging for release 1.20.1
  Support 'street2' field for PayflowExpress UK
  Add x_solution_ID to AuthorizeNet for tracking purposes
  SagePay Form: Map billing address to shipping address if shipping address isn't given
  Packaging for 1.20.0
  Packaging for release 1.19.0
  Add support for custom currency at Gateway level. Helped by @rymai
  Add support for custom ECI
  Beanstream: cover the case when source for purchase is a Secure Profile
  Beanstream: fix tests to use new api #refund instead of #credit
  Orbital: Various fixes and adjustments:
  Fix Samurai tests in 2.3.x related to AR::Errors and mocking
  Refactor Samurai gateway
  Add FeeFighters Samurai Gateway support
  Lock the money gem to 3.7.1 or less since newer versions break in 1.9
  Moneris: respect passed in test option
  Payflow Link: use passed in user, or default to the login
  Add support for all signature procedures. Helped by @rymai
  Add refund method to some gateways that do referenced credits
  Payflow Link: Use secure token for passing data to PayPal
  ...

Conflicts:
	README.rdoc
  • Loading branch information...
commit 986d4588ea25388549b68b0fab09b9f714509187 2 parents 6a00466 + 44ad856
Verestiuc Vlad vvlad authored
Showing with 19,485 additions and 10,215 deletions.
  1. +7 −0 .gitignore
  2. +10 −0 .travis.yml
  3. +1 −0  .yardopts
  4. +201 −2 CHANGELOG
  5. +92 −1 CONTRIBUTORS
  6. +20 −0 Gemfile
  7. +63 −0 GettingStarted.md
  8. +181 −0 README.md
  9. +8 −1 Rakefile
  10. +14 −4 activemerchant.gemspec
  11. +6 −7 lib/active_merchant.rb
  12. +2 −2 lib/active_merchant/billing/avs_result.rb
  13. +159 −58 lib/active_merchant/billing/credit_card.rb
  14. +3 −3 lib/active_merchant/billing/credit_card_methods.rb
  15. +16 −9 lib/active_merchant/billing/gateway.rb
  16. +52 −12 lib/active_merchant/billing/gateways/authorize_net.rb
  17. +134 −12 lib/active_merchant/billing/gateways/authorize_net_cim.rb
  18. +308 −0 lib/active_merchant/billing/gateways/barclays_epdq.rb
  19. +39 −2 lib/active_merchant/billing/gateways/beanstream.rb
  20. +68 −26 lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb
  21. +11 −0 lib/active_merchant/billing/gateways/blue_pay.rb
  22. +58 −18 lib/active_merchant/billing/gateways/bogus.rb
  23. +1 −1  lib/active_merchant/billing/gateways/braintree/braintree_common.rb
  24. +133 −35 lib/active_merchant/billing/gateways/braintree_blue.rb
  25. +23 −0 lib/active_merchant/billing/gateways/card_save.rb
  26. +25 −1 lib/active_merchant/billing/gateways/cyber_source.rb
  27. +6 −2 lib/active_merchant/billing/gateways/data_cash.rb
  28. +8 −2 lib/active_merchant/billing/gateways/efsnet.rb
  29. +2 −1  lib/active_merchant/billing/gateways/elavon.rb
  30. +274 −0 lib/active_merchant/billing/gateways/epay.rb
  31. +264 −0 lib/active_merchant/billing/gateways/eway_managed.rb
  32. +5 −0 lib/active_merchant/billing/gateways/exact.rb
  33. +168 −0 lib/active_merchant/billing/gateways/federated_canada.rb
  34. +7 −2 lib/active_merchant/billing/gateways/first_pay.rb
  35. +132 −92 lib/active_merchant/billing/gateways/garanti.rb
  36. +250 −0 lib/active_merchant/billing/gateways/ideal/ideal_base.rb
  37. +13 −0 lib/active_merchant/billing/gateways/ideal/ideal_rabobank.pem
  38. +29 −0 lib/active_merchant/billing/gateways/ideal/ideal_response.rb
  39. +55 −0 lib/active_merchant/billing/gateways/ideal_rabobank.rb
  40. +10 −5 lib/active_merchant/billing/gateways/iridium.rb
  41. +12 −6 lib/active_merchant/billing/gateways/jetpay.rb
  42. +6 −1 lib/active_merchant/billing/gateways/linkpoint.rb
  43. +10 −8 lib/active_merchant/billing/gateways/merchant_e_solutions.rb
  44. +7 −1 lib/active_merchant/billing/gateways/merchant_ware.rb
  45. +10 −2 lib/active_merchant/billing/gateways/moneris.rb
  46. +11 −5 lib/active_merchant/billing/gateways/netaxept.rb
  47. +13 −0 lib/active_merchant/billing/gateways/nmi.rb
  48. +108 −57 lib/active_merchant/billing/gateways/ogone.rb
  49. +274 −0 lib/active_merchant/billing/gateways/optimal_payment.rb
  50. +329 −0 lib/active_merchant/billing/gateways/orbital.rb
  51. +46 −0 lib/active_merchant/billing/gateways/orbital/orbital_soft_descriptors.rb
  52. +15 −10 lib/active_merchant/billing/gateways/pay_junction.rb
  53. +8 −4 lib/active_merchant/billing/gateways/paybox_direct.rb
  54. +26 −9 lib/active_merchant/billing/gateways/payflow.rb
  55. +11 −11 lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb
  56. +2 −2 lib/active_merchant/billing/gateways/payflow/payflow_express_response.rb
  57. +122 −38 lib/active_merchant/billing/gateways/payflow_express.rb
  58. +7 −2 lib/active_merchant/billing/gateways/payment_express.rb
  59. +5 −5 lib/active_merchant/billing/gateways/paypal.rb
  60. +39 −11 lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb
  61. +26 −15 lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb
  62. +1 −1  lib/active_merchant/billing/gateways/paypal_ca.rb
  63. +54 −13 lib/active_merchant/billing/gateways/paypal_express.rb
  64. +8 −3 lib/active_merchant/billing/gateways/paypal_express_common.rb
  65. +201 −0 lib/active_merchant/billing/gateways/paystation.rb
  66. +9 −3 lib/active_merchant/billing/gateways/plugnpay.rb
  67. +5 −0 lib/active_merchant/billing/gateways/psigate.rb
  68. +297 −0 lib/active_merchant/billing/gateways/qbms.rb
  69. +282 −0 lib/active_merchant/billing/gateways/quantum.rb
  70. +153 −69 lib/active_merchant/billing/gateways/quickpay.rb
  71. +192 −77 lib/active_merchant/billing/gateways/realex.rb
  72. +7 −4 lib/active_merchant/billing/gateways/sage_pay.rb
  73. +120 −0 lib/active_merchant/billing/gateways/samurai.rb
  74. +39 −3 lib/active_merchant/billing/gateways/secure_pay_au.rb
  75. +6 −1 lib/active_merchant/billing/gateways/skip_jack.rb
  76. +9 −3 lib/active_merchant/billing/gateways/smart_ps.rb
  77. +212 −0 lib/active_merchant/billing/gateways/stripe.rb
  78. +7 −2 lib/active_merchant/billing/gateways/trust_commerce.rb
  79. +13 −184 lib/active_merchant/billing/gateways/usa_epay.rb
  80. +1,496 −0 lib/active_merchant/billing/gateways/usa_epay_advanced.rb
  81. +194 −0 lib/active_merchant/billing/gateways/usa_epay_transaction.rb
  82. +6 −1 lib/active_merchant/billing/gateways/verifi.rb
  83. +1 −1  lib/active_merchant/billing/gateways/viaklix.rb
  84. +280 −0 lib/active_merchant/billing/gateways/worldpay.rb
  85. +2 −2 lib/active_merchant/billing/integrations/action_view_helper.rb
  86. +1 −1  lib/active_merchant/billing/integrations/bogus.rb
  87. +1 −1  lib/active_merchant/billing/integrations/chronopay.rb
  88. +7 −3 lib/active_merchant/billing/integrations/direc_pay.rb
  89. +39 −27 lib/active_merchant/billing/integrations/direc_pay/helper.rb
  90. +47 −0 lib/active_merchant/billing/integrations/directebanking.rb
  91. +90 −0 lib/active_merchant/billing/integrations/directebanking/helper.rb
  92. +120 −0 lib/active_merchant/billing/integrations/directebanking/notification.rb
  93. +11 −0 lib/active_merchant/billing/integrations/directebanking/return.rb
  94. +30 −0 lib/active_merchant/billing/integrations/dwolla.rb
  95. +31 −0 lib/active_merchant/billing/integrations/dwolla/helper.rb
  96. +55 −0 lib/active_merchant/billing/integrations/dwolla/notification.rb
  97. +38 −0 lib/active_merchant/billing/integrations/dwolla/return.rb
  98. +48 −0 lib/active_merchant/billing/integrations/e_payment_plans.rb
  99. +34 −0 lib/active_merchant/billing/integrations/e_payment_plans/helper.rb
  100. +84 −0 lib/active_merchant/billing/integrations/e_payment_plans/notification.rb
  101. +1 −1  lib/active_merchant/billing/integrations/gestpay.rb
  102. +13 −8 lib/active_merchant/billing/integrations/helper.rb
  103. +1 −1  lib/active_merchant/billing/integrations/hi_trust.rb
  104. +26 −0 lib/active_merchant/billing/integrations/moneybookers.rb
  105. +59 −0 lib/active_merchant/billing/integrations/moneybookers/helper.rb
  106. +129 −0 lib/active_merchant/billing/integrations/moneybookers/notification.rb
  107. +2 −2 lib/active_merchant/billing/integrations/nochex.rb
  108. +1 −1  lib/active_merchant/billing/integrations/notification.rb
  109. +21 −0 lib/active_merchant/billing/integrations/payflow_link.rb
  110. +100 −0 lib/active_merchant/billing/integrations/payflow_link/helper.rb
  111. +78 −0 lib/active_merchant/billing/integrations/payflow_link/notification.rb
  112. +1 −1  lib/active_merchant/billing/integrations/paypal.rb
  113. +6 −2 lib/active_merchant/billing/integrations/quickpay.rb
  114. +1 −1  lib/active_merchant/billing/integrations/quickpay/helper.rb
  115. +1 −1  lib/active_merchant/billing/integrations/quickpay/notification.rb
  116. +6 −1 lib/active_merchant/billing/integrations/return.rb
  117. +22 −4 lib/active_merchant/billing/integrations/sage_pay_form/helper.rb
  118. +6 −0 lib/active_merchant/billing/integrations/sage_pay_form/notification.rb
  119. +5 −1 lib/active_merchant/billing/integrations/sage_pay_form/return.rb
  120. +2 −3 lib/active_merchant/billing/integrations/two_checkout.rb
  121. +5 −5 lib/active_merchant/billing/integrations/two_checkout/notification.rb
  122. +33 −0 lib/active_merchant/billing/integrations/valitor.rb
  123. +86 −0 lib/active_merchant/billing/integrations/valitor/helper.rb
  124. +13 −0 lib/active_merchant/billing/integrations/valitor/notification.rb
  125. +97 −0 lib/active_merchant/billing/integrations/valitor/response_fields.rb
  126. +13 −0 lib/active_merchant/billing/integrations/valitor/return.rb
  127. +27 −0 lib/active_merchant/billing/integrations/world_pay.rb
  128. +100 −0 lib/active_merchant/billing/integrations/world_pay/helper.rb
  129. +160 −0 lib/active_merchant/billing/integrations/world_pay/notification.rb
  130. +0 −14 lib/active_merchant/common.rb
  131. +0 −172 lib/active_merchant/common/connection.rb
  132. +0 −328 lib/active_merchant/common/country.rb
  133. +0 −26 lib/active_merchant/common/error.rb
  134. +0 −24 lib/active_merchant/common/post_data.rb
  135. +0 −47 lib/active_merchant/common/posts_data.rb
  136. +0 −16 lib/active_merchant/common/requires_parameters.rb
  137. +0 −18 lib/active_merchant/common/utils.rb
  138. +0 −76 lib/active_merchant/common/validateable.rb
  139. +1 −1  lib/active_merchant/version.rb
  140. +0 −7,815 lib/certs/cacert.pem
  141. +3 −0  rails/init.rb
  142. +39 −0 test/comm_stub.rb
  143. +110 −19 test/fixtures.yml
  144. +227 −2 test/remote/gateways/remote_authorize_net_cim_test.rb
  145. +14 −0 test/remote/gateways/remote_authorize_net_test.rb
  146. +200 −0 test/remote/gateways/remote_barclays_epdq_test.rb
  147. +67 −5 test/remote/gateways/remote_beanstream_test.rb
  148. +105 −0 test/remote/gateways/remote_blue_pay_test.rb
  149. +77 −40 test/remote/gateways/remote_braintree_blue_test.rb
  150. +59 −0 test/remote/gateways/remote_card_save_test.rb
  151. +23 −1 test/remote/gateways/remote_cyber_source_test.rb
  152. +105 −0 test/remote/gateways/remote_epay_test.rb
  153. +67 −0 test/remote/gateways/remote_eway_managed_test.rb
  154. +91 −0 test/remote/gateways/remote_federated_canada_test.rb
  155. +11 −9 test/remote/gateways/remote_garanti_test.rb
  156. +121 −0 test/remote/gateways/remote_ideal_rabobank_test.rb
  157. +2 −0  test/remote/gateways/remote_iridium_test.rb
  158. +11 −5 test/remote/gateways/remote_jetpay_test.rb
  159. +3 −3 test/remote/gateways/remote_netaxept_test.rb
  160. +106 −0 test/remote/gateways/remote_nmi_test.rb
  161. +92 −9 test/remote/gateways/remote_ogone_test.rb
  162. +143 −0 test/remote/gateways/remote_optimal_payment_test.rb
  163. +171 −0 test/remote/gateways/remote_orbital_test.rb
  164. +4 −5 test/remote/gateways/remote_pay_junction_test.rb
  165. +2 −0  test/remote/gateways/remote_paybox_direct_test.rb
  166. +113 −0 test/remote/gateways/remote_paystation_test.rb
  167. +96 −0 test/remote/gateways/remote_qbms_test.rb
  168. +75 −0 test/remote/gateways/remote_quantum_test.rb
  169. +16 −14 test/remote/gateways/remote_quickpay_test.rb
  170. +210 −0 test/remote/gateways/remote_quickpay_v4_test.rb
  171. +89 −8 test/remote/gateways/remote_realex_test.rb
  172. +58 −0 test/remote/gateways/remote_samurai_test.rb
  173. +71 −6 test/remote/gateways/remote_secure_pay_au_test.rb
  174. +106 −0 test/remote/gateways/remote_stripe_test.rb
  175. +427 −0 test/remote/gateways/remote_usa_epay_advanced_test.rb
  176. +5 −5 test/remote/gateways/{remote_usa_epay_test.rb → remote_usa_epay_transaction_test.rb}
  177. +77 −0 test/remote/gateways/remote_worldpay_test.rb
  178. +1 −1  test/remote/integrations/remote_gestpay_integration_test.rb
  179. +99 −0 test/remote/integrations/remote_integration_helper.rb
  180. +157 −0 test/remote/integrations/remote_valitor_integration_test.rb
  181. +21 −1 test/test_helper.rb
  182. +0 −137 test/unit/connection_test.rb
  183. +0 −33 test/unit/country_code_test.rb
  184. +0 −70 test/unit/country_test.rb
  185. +7 −4 test/unit/credit_card_methods_test.rb
  186. +83 −47 test/unit/credit_card_test.rb
  187. +209 −1 test/unit/gateways/authorize_net_cim_test.rb
  188. +86 −9 test/unit/gateways/authorize_net_test.rb
  189. +445 −0 test/unit/gateways/barclays_epdq_test.rb
  190. +24 −2 test/unit/gateways/beanstream_test.rb
  191. +12 −0 test/unit/gateways/blue_pay_test.rb
  192. +63 −7 test/unit/gateways/bogus_test.rb
  193. +88 −4 test/unit/gateways/braintree_blue_test.rb
  194. +0 −4 test/unit/gateways/braintree_orange_test.rb
  195. +1 −1  test/unit/gateways/braintree_test.rb
  196. +277 −0 test/unit/gateways/card_save_test.rb
  197. +20 −7 test/unit/gateways/cyber_source_test.rb
  198. +20 −1 test/unit/gateways/data_cash_test.rb
  199. +17 −0 test/unit/gateways/efsnet_test.rb
  200. +132 −0 test/unit/gateways/epay_test.rb
  201. +359 −0 test/unit/gateways/eway_managed_test.rb
  202. +1 −1  test/unit/gateways/eway_test.rb
  203. +51 −1 test/unit/gateways/exact_test.rb
  204. +141 −0 test/unit/gateways/federated_canada_test.rb
  205. +18 −12 test/unit/gateways/first_pay_test.rb
  206. +82 −40 test/unit/gateways/garanti_test.rb
  207. +320 −0 test/unit/gateways/ideal_rabobank_test.rb
  208. +30 −4 test/unit/gateways/iridium_test.rb
  209. +22 −1 test/unit/gateways/jetpay_test.rb
  210. +9 −7 test/unit/gateways/merchant_e_solutions_test.rb
  211. +20 −0 test/unit/gateways/merchant_ware_test.rb
  212. +15 −1 test/unit/gateways/moneris_test.rb
  213. +30 −0 test/unit/gateways/netaxept_test.rb
  214. +12 −0 test/unit/gateways/nmi_test.rb
  215. +152 −25 test/unit/gateways/ogone_test.rb
  216. +223 −0 test/unit/gateways/optimal_payment_test.rb
  217. +70 −0 test/unit/gateways/orbital_test.rb
  218. +69 −0 test/unit/gateways/pay_junction_test.rb
  219. +19 −0 test/unit/gateways/paybox_direct_test.rb
  220. +10 −2 test/unit/gateways/payflow_express_test.rb
  221. +30 −0 test/unit/gateways/payflow_test.rb
  222. +201 −43 test/unit/gateways/paypal_express_test.rb
  223. +22 −0 test/unit/gateways/paypal_test.rb
  224. +331 −0 test/unit/gateways/paystation_test.rb
  225. +20 −0 test/unit/gateways/plugnpay_test.rb
  226. +16 −2 test/unit/gateways/psigate_test.rb
  227. +241 −0 test/unit/gateways/qbms_test.rb
  228. +114 −0 test/unit/gateways/quantum_test.rb
  229. +1 −1  test/unit/gateways/quickpay_test.rb
  230. +256 −9 test/unit/gateways/realex_test.rb
  231. +204 −0 test/unit/gateways/samurai_test.rb
  232. +104 −3 test/unit/gateways/secure_pay_au_test.rb
  233. +26 −1 test/unit/gateways/skip_jack_test.rb
  234. +241 −0 test/unit/gateways/stripe_test.rb
  235. +788 −0 test/unit/gateways/usa_epay_advanced_test.rb
  236. +25 −122 test/unit/gateways/usa_epay_test.rb
  237. +136 −0 test/unit/gateways/usa_epay_transaction_test.rb
  238. +20 −0 test/unit/gateways/verifi_test.rb
  239. +345 −0 test/unit/gateways/worldpay_test.rb
  240. +2 −2 test/unit/integrations/bogus_module_test.rb
  241. +2 −2 test/unit/integrations/chronopay_module_test.rb
  242. +11 −2 test/unit/integrations/direc_pay_module_test.rb
  243. +14 −0 test/unit/integrations/dwolla_module_test.rb
  244. +24 −0 test/unit/integrations/e_payment_plans_module_test.rb
  245. +2 −2 test/unit/integrations/gestpay_module_test.rb
  246. +30 −10 test/unit/integrations/helpers/direc_pay_helper_test.rb
  247. +52 −0 test/unit/integrations/helpers/directebanking_helper_test.rb
  248. +37 −0 test/unit/integrations/helpers/dwolla_helper_test.rb
  249. +56 −0 test/unit/integrations/helpers/e_payment_plans_helper_test.rb
  250. +84 −0 test/unit/integrations/helpers/moneybookers_helper_test.rb
  251. +173 −0 test/unit/integrations/helpers/payflow_link_helper_test.rb
  252. +1 −1  test/unit/integrations/helpers/paypal_helper_test.rb
  253. +72 −6 test/unit/integrations/helpers/sage_pay_form_helper_test.rb
  254. +2 −2 test/unit/integrations/helpers/two_checkout_helper_test.rb
Sorry, we could not display the entire diff because it was too big.
7 .gitignore
View
@@ -3,3 +3,10 @@
*.swp
*.swo
pkg
+.rvmrc
+vendor/cache
+.bundle
+
+# ignore Gemfile.lock because we support multiple versions of Rails and don't want to ship locked version requirements
+Gemfile.lock
+.yardoc
10 .travis.yml
View
@@ -0,0 +1,10 @@
+rvm:
+ - 1.8.7
+ - 1.9.2
+ - rbx
+ - ree
+
+script: "bundle exec rake test:units"
+
+notifications:
+ disabled: true
1  .yardopts
View
@@ -0,0 +1 @@
+- GettingStarted.md
203 CHANGELOG
View
@@ -1,10 +1,209 @@
= ActiveMerchant CHANGELOG
+== Version 1.20.1 (December 22, 2011)
+
+* PayflowExpressUk: Fix parsing street2 from response [odorcicd]
+* AuthorizeNet: Support tracking id [odorcicd]
+* SagePay Form: Map billing address to shipping address [jduff]
+
+== Version 1.20.0 (November 14, 2011)
+
+* Add support for USA ePay Advanced SOAP interface [matthewcalebsmith/jduff]
+* Beanstram: fix purchase with Secure Profile [pitr/jduff]
+* Orbital: various fixes [Soleone]
+* Add Samuari gateway by Fee Fighters [jkrall/odorcicd]
+* Lock money gem to 3.7.1 or less since newer versions break in 1.9 [jduff]
+* Braintree: handle gateway rejected transactions gracefully [braintreeps/jduff]
+* Ogone: support different signature encryptors, custom currency and eci [ZenCocoon/rymai/jduff]
+* Payflow Link: use secure token [jduff]
+* Added refund method to Exact, Pay Junction and Skip Jack gateways [jduff]
+* Elavon: added test url [kylekeesling/jduff]
+* Fix redundent errors when credit card is expired [castiglione/jduff]
+* Two Checkout: update service url [vampirechicken/jduff]
+
+== Version 1.18.1 (September 23, 2011)
+
+* Braintree: allow setting merchant_account_id on initialize [jduff]
+* Realex: only send letters and numbers in shipping code field [Soleone]
+
+== Version 1.18.0 (September 23, 2011)
+
+* NoChex: Update the URL that payment requests are posted to [caseywhalen/jduff]
+* QBMS: fixed test mode check [Soleone]
+* Realex: encode avs info with shipping address [Soleone]
+* Add Dwolla offsite gateway [armsteadj1/jduff]
+* Eway: pass email, customer, description and options to store [moklett/tobi]
+* New dependency: active_utils gem [odorcicd]
+* Optimal Payments: fix test mode check [jduff]
+
+== Version 1.17.0 (August 23, 2011)
+
+* Add Payflow Link integration [jduff]
+* Add CardSave gateway [MrJaba/jduff]]
+* Quickpay: Support protocal version 4 and fraud parameters [anderslemke/jduff]
+* Authorize.net: Add status_recurring [mm1/jduff]
+* Paypal Express: Support specifying :items with purchase [sivabudh/jduff]
+* ePay: Add Sweden and Norway to supported countries [ePay/jduff]
+* Brainreee: Support passing merchant_account_id parameter [braintreeps/jduff]
+* Paypal Express: Remove deprecated Address field in favor of ShipToAddress[jduff]
+* Add Optimal Payments gateway [jamie/jduff]
+* Documentation improvements [dasch/nhemsley/jstorimer/jduff]
+* Authorize.Net: Pass through first name, last name, and zip for refunds. [ntalbott]
+
+== Version 1.16.0 (July 18, 2011)
+
+* Bogus: Support referenced transactions for #authorize, #purchase, #recurring and
+#credit [dasch/jduff]
+* Payment Express: Update gateway url [bayan/titanous]
+* Moneybookers: Send country and account_name if provided [Soleone]
+* Moneris: Add Diners Club and Discover [Soleone]
+* Cybersource: add auth_reversal support [jeberly/titanous]
+* WorldPay: Update endpoint URLs for offsite gateway [Soleone]
+* Worldpay: Add JCB and add Maestro [Soleone]
+* Authorize.net: Add Diners Club and JCB [Soleone]
+* Quickpay: Add testmode for subscribe and authorize [dasch/jduff]
+* Orbital: fix handling of phone numbers. [ntalbott]
+* Braintree: Add Diners Club [cody]
+* Add ePaymentPlans offsite payment [robertomiranda/Soleone]
+* Add Stripe gateway [boucher/titanous]
+* Add Paystation gateway [nikz/jduff]
+* Bump minimum ActiveSupport version to 2.3.11 [titanous]
+* Use securerandom from stdlib not active_support [phlipper/jduff]
+
+== Version 1.15.0 (May 12, 2011)
+
+* DirecPay: Fix address to not include address2 twice in some cases [Soleone]
+* DirecPay: Send company if available [Soleone]
+* Realex: Fix hash signature [ntalbott/Soleone]
+* SecurePay AU: Update remote tests [ntalbott]
+* SecurePay AU: Fix method arity for #capture, #refund, #credit and #void [Soleone]
+* Barclays ePDQ: Make response parsing more robust [Soleone]
+* Payflow Express: Add line item support [wolframarnold]
+* Payflow Express: Add comment field support [wolframarnold]
+* Payflow: Add more optional fields [wolframarnold]
+* Beanstream/Paypal: Fix CREDIT_DEPRECATION_MESSAGE errors [Jonathan Rudenberg]
+* BraintreeBlue: Return a hash instead of a transaction object [braintreeps]
+* BraintreeBlue: Return proper AVS/CVV values [braintreeps]
+* Bogus: Add #recurring [trwomey]
+* Make Validateable compatible with ActiveModel [CodeMonkeySteve]
+* Add DirectEBanking offsite gateway [Gerwin Brunner/Soleone]
+* ActiveSupport 3.1 beta support [cgriego]
+
+== Version 1.14.0 (Apr 29, 2011)
+
+* SagePayForm: Implement #cancelled? for Return. [wisq]
+* Add #cancelled? to Integrations::Return [wisq]
+* Bogus gateway: Add refund support and better tests [wisq]
+* Beanstream: Add support for storing cards [duffomelia]
+* eWay: Add support for storing cards [duffomelia]
+* Add validation mode to update profile request [Ken Miller]
+* Authorize.net CIM: Add oldLiveMode [ntalbott]
+* Authorize.net CIM: Add extra transaction types [Ken Miller]
+* JetPay: gateway tweaks [ntalbott]
+* Deprecate a bunch more #credit methods [ntalbott]
+* RealEx: Add authorize/capture/credit/void [ntalbott]
+* SecurePay AU: Add authorize/capture/credit/void [ntalbott]
+* PayPal Express: Make response parsing more robust [ntalbott]
+* Test deprecation warnings; add deprecation line numbers [ntabott]
+* Add Orbital direct gateway [ntalbott]
+* Add WorldPay direct gateway [ntalbott]
+
+== Version 1.13.0 (Apr 19, 2011)
+
+* Add a Gemfile for optional bundler support [ssoroka]
+* Stop using has_rdoc= when rubygems version is 1.7.0 or greater, since it's deprecated [ssoroka]
+* Add tax field to braintree [wisq]
+* Quickpay: Also add Sweden as supported country [Soleone]
+* Adding refund method for gateways that are using the credit method for referenced based refunds, added deprecation worning to the credit method [John Duff]
+* Return the Braintree transaction id in the response for void and refund transaction calls [John Duff]
+* PayPal Express: Extract phone number from address if no contact phone was sent [Soleone]
+* Unify all offsite gateways that verify the signature of Returns or Notifications by always using the #acknowledge method and calling the secret :credential2 [Soleone]
+* Valitor: Change name of credential for Return and Notification from :password to :credential2 in symmetry with the other Integrations [Soleone]
+* Moneybookers: Add support for tracking token [Soleone]
+* Moneybookers: Require credential when creating Notifications instead of adding an argument to #acknowledge [Soleone]
+* Moneybookers: Fix Notification to return correct status [Soleone]
+* Support default Return class for all Integrations that don't use returns [Soleone]
+* Add support for passing additional options when creating a Notification to all Integrations [Soleone]
+* Update BraintreeBlue#refund to have consistent method signature [Jonathan Rudenberg]
+* Add rails/init.rb for gem campatability in Rails [Rūdolfs Ošiņš]
+* Fix Paypal Express response parser [Jonathan Rudenberg]
+* Braintree/Transax: Add tax field [wisq]
+
+== Version 1.12.1 (Mar 21, 2011)
+
+* Ogone: Make sure response.params is a real Hash [Soleone]
+* WorldPay: Fix service_url in production mode [Soleone]
+
+== Version 1.12.0 (Mar 1, 2011)
+
+* DirecPay: Send phone number as mobile phone by default [Soleone]
+* Support sending line items for PayPal Express transactions [Jonathan Rudenberg]
+* Update PayPal Express XML format to latest version [Jonathan Rudenberg]
+* Fix custom image header for PayPal Express [mwagg]
+* Add InvoiceID and OrderDescription to PayPal Express Authorize and Capture [cody]
+* Add Moneybookers integration [Alex Diakov]
+* Add QBMS (Quickbooks Merchant Services) gateway [ntalbott]
+* Add NMI gateway [ntalbott]
+* Make fully compatible with Rails 2 & 3, and Ruby 1.8 & 1.9 [ntalbott]
+* Authorize.Net: Only return AVS message for AVS-related reason codes. [ntalbott]
+* Add Federated Canada gateway [ntalbott]
+* Garanti: Fix text normalization for nil values [Selem Delul]
+* Valitor: Always send amount without any decimal places [Soleone]
+* Add WorldPay integration [Soleone]
+
+== Version 1.11.0 (Feb 11, 2011)
+
+* Bump dependency for activesupport from 2.3.2 to 2.3.8 [Soleone]
+* Garanti: Normalize text in xml fields for non-standard characters [Selem Delul]
+* Garanti: Make sure order number does not contain illegal characters [Soleone]
+* Fix ActionView tests for ActiveSupport 3.0.4 [Soleone]
+* DirecPay: Make address information editable by default [Soleone]
+* Fix ePDQ credit to expect and handle full authorization [Nathaniel Talbott]
+* Add Barclays ePDQ Gateway [Nathaniel Talbott]
+* Add default fixture for Garanti and don't use fixture for Garanti [cody]
+* Add cms param for ePay [ePay]
+* Add Valitor Integration [Nathaniel Talbott]
+
+== Version 1.10.0 (Jan 20, 2011)
+
+* PayPal Express: Support returning payer phone number [Soleone]
+* Fix ePay to correctly send order number [Soleone]
+* Add BluePay Gateway [Nathaniel Talbott]
+* Add Quantum Gateway [Joshua Lippiner]
+* Add iDEAL/Rabobank gateway [Jonathan Rudenberg]
+* SagePayForm: Added send_email_confirmation (default false) to enable confirmation emails [wisq]
+
+== Version 1.9.4 (Jan 5, 2011)
+
+* Update Garanti gateway to integrate with new API [Selem Delul]
+
+== Version 1.9.3 (December 17, 2010)
+
+* Fix BBS Netaxept to change transaction type from C (for MOTO: mail order telephone order) to M (for credit card orders) [Soleone]
+* Fix Iridium and ePay to work with any object that responds to credit card methods not only ActiveMerchant::CreditCard objects
+
+== Version 1.9.2 (December 9, 2010)
+
+* Add support for PayPal mobile payments [wisq]
+* Add ePay gateway [ePay, Jonathan Rudenberg]
+* Allow access to the raw HTTP response [Jonathan Rudenberg]
+
+== Version 1.9.1 (November 24, 2010)
+
+* PayPal Express and PayPal Pro: Send JPY currency correctly without decimals [Soleone]
+* Netaxept: Make sure password (token) is URL escaped and update remote tests for updated server behavior [Soleone]
+* DirecPay: Add support for additional options in Return class and add convenience method to get transaction status update [Soleone]
+* Add new alias credit_card.brand for credit_card.type and handle the brand correctly in Netaxept [Soleone]
+* Iridium: Do not depend on ExpiryDate class for credit_card [Soleone]
+* PayFlow: Use same timeout of 60 seconds in HTTP header and XML for all requests [Soleone]
+* PayPal Website Payments Pro CA no longer supports American Express cards [Soleone]
+* Updated BIN ranges for Discover to match recent documents [kaunartist]
+
== Version 1.9.0 (October 14, 2010)
* Add support for DirecPay gateway [Soleone]
-* Add SagePay Form integration gateway [Adrian Irving-Beer]
-* Allow Return class to include a Notification for gateways that treat the direct response as a notification [Adrian Irving-Beer]
+* Add SagePay Form integration gateway [wisq]
+* Allow Return class to include a Notification for gateways that treat the direct response as a notification [wisq]
* Add support for PayboxDirect gateway [Donald Piret]
* Add support for SecureNet gateway [Kal]
* Add support for the Inspire gateway [ryan r. smith]
93 CONTRIBUTORS
View
@@ -26,6 +26,7 @@ Linkpoint Gateway
eWay Gateway
* Originally contributed by Lucas Carlson (mailto:lucas@rufy.com)
+* Managed Payments support by Jason Stirk with improvements by Keith Pitt
CardStream Gateway
@@ -83,6 +84,7 @@ PaypalNVGateway (Apr 12, 2008)
Beanstream (May 13, 2008)
* Created by xiaobozz ( xiaobozzz at gmail dot com )
+* Secure Profiles support by Forrest Zeisler (http://github.com/forrest)
Sage (June, 2008)
@@ -167,4 +169,93 @@ SagePay Form Offsite Gateway (October 14, 2010)
DirecPay Gateway (October 14, 2010)
-* Soleone
+* Soleone
+
+ePay Gateway (November 23, 2010)
+
+* Original code by ePay (epay.dk)
+* Refactored by Jonathan Rudenberg
+
+iDEAL/Rabobank Gateway (January 10, 2011)
+
+* Original code by Soemirno Kartosoewito
+* Refactored by Cody Fauser
+* Refactored and updated by Jonathan Rudenberg
+
+Quantum Gateway
+
+* Joshua Lippiner
+* Refactored by Nathaniel Talbott
+
+BluePay Gateway
+
+* Mel Sleight
+* Refactored by Nathaniel Talbott
+
+Valitor Integration (January 2011)
+
+* Nathaniel Talbott
+* Sponsored by Sævar Öfjörð Magnússon
+
+Barclays ePDQ
+
+* Original code by Rob W (rfwatson)
+* Refactored by Nathaniel Talbott
+
+Federated Canada
+
+* Bob Larrick (deathbob)
+
+NMI
+
+* Nathaniel Talbott (ntalbott)
+
+QBMS
+
+* Will Glozer (wg)
+
+WorldPay Integration (Feb 17, 2011)
+
+* Original code by Unknown from this patch: https://jadedpixel.lighthouseapp.com/projects/11599/tickets/3-patch-integration-support-for-worldpay-uk
+* Refactored by Soleone
+
+WorldPay Gateway
+
+* Original code by Amit kumar (ask4amit@gmail.com)
+* Refactored by Nathaniel Talbott (ntalbott)
+
+Orbital Paymentech Gateway (July, 2009)
+
+* Sam Vincent - http://ecommerce.versapay.com
+
+DIRECTebanking - Payment Network AG (May, 2011)
+
+* Gerwin Brunner (Vilango)
+
+Stripe
+
+* Ross Boucher (boucher)
+
+Paystation (July, 2011)
+
+* Nik Wakelin (nikz)
+
+ePaymentPlans offsite gatway (June, 2011)
+
+* Roberto Miranda (robertomiranda)
+
+Optimal Payments (August, 2011)
+
+* Jamie Macey (jamie)
+
+CardSave (August, 2011)
+
+* Tom Crinson (MrJaba)
+
+Dwolla (September, 2011)
+
+* James Armstead (armsteadj1)
+
+Samurai (November, 2011)
+
+* Joshua Krall (jkrall)
20 Gemfile
View
@@ -0,0 +1,20 @@
+source :rubygems
+gemspec
+
+group :test do
+ gem 'json-jruby', :platforms => :jruby
+ gem 'jruby-openssl', :platforms => :jruby
+
+ # gateway-specific dependencies, keeping these gems out of the gemspec
+ gem 'samurai', '>= 0.2.25'
+end
+
+group :remote_test do
+ gem 'mechanize'
+ gem 'launchy'
+ gem 'mongrel', '1.2.0.pre2', :platforms => :ruby
+
+ # gateway-specific dependencies, keeping these gems out of the gemspec
+ gem 'samurai', '>= 0.2.25'
+end
+
63 GettingStarted.md
View
@@ -0,0 +1,63 @@
+# Getting Started with Active Merchant
+
+Before getting started using Active Merchant, a bit of terminology is needed.
+
+In order to process credit card payments, your application needs to interface with a payment
+gateway. In Active Merchant, these are represented as subclasses of {ActiveMerchant::Billing::Gateway}.
+
+## Gateway Operations
+
+A typical interaction consists of the application obtaining the necessary credit card credentials
+(card number, expiry date, etc.) and asking the gateway to *authorize* the required amount on the
+card holder's credit card.
+
+If the authorization is successful, the funds are available and you can ask the gateway to *capture*
+them to your account. If the capture is completed, the payment has been made.
+
+When combined into a single operation, this is called a *purchase*.
+
+All of these operations are performed on an instance of a Gateway subclass:
+
+ gateway = SomeGateway.new
+
+ # Amounts are always specified in cents, so this is
+ # equal to $10.
+ response = gateway.purchase(1000, credit_card)
+
+Both `#authorize`, `#capture` and `#purchase` return a {ActiveMerchant::Billing::Response} instance.
+This object contains the details of the operation, most notably whether it was successful.
+
+ if response.success?
+ puts "Payment complete!"
+ else
+ puts "Payment failed: #{response.message}"
+ end
+
+As can be seen, {ActiveMerchant::Billing::Response#success?} returns whether the operation completed
+successfully. If `false`, the error message is available in `#message`.
+
+## Handling Credit Cards
+
+In Active Merchant, credit cards are represented by instances of {ActiveMerchant::Billing::CreditCard}.
+Instantiating such an object is simple:
+
+ credit_card = ActiveMerchant::Billing::CreditCard.new(
+ :first_name => 'Steve',
+ :last_name => 'Smith',
+ :month => '9',
+ :year => '2014',
+ :type => 'visa',
+ :number => '4242424242424242')
+
+Most often, though, you'll be using user-supplied data. In a typical Rails controller:
+
+ credit_card = ActiveMerchant::Billing::CreditCard.new(params[:credit_card])
+
+### Validation
+
+While the above attributes are always required for a `CreditCard` to be valid, some gateways also
+require a *verification value*, e.g. a CVV code, to be given.
+
+Validating a credit card is as simple as calling `#valid?`, which
+returns `true` only if the credentials are syntactically valid. If there are any errors or omissions,
+the `#errors` attribute will be non-empty.
181 README.md
View
@@ -0,0 +1,181 @@
+# Active Merchant
+
+Active Merchant is an extraction from the e-commerce system [Shopify](http://www.shopify.com).
+Shopify's requirements for a simple and unified API to access dozens of different payment
+gateways with very different internal APIs was the chief principle in designing the library.
+
+Active Merchant has been in production use since June 2006 and is now used in most modern
+Ruby applications which deal with financial transactions.
+
+It was developed for usage in Ruby on Rails web applications and integrates seamlessly
+as a plugin but it also works excellently as a stand alone library.
+
+See {file:GettingStarted.md} if you want to learn more about using Active Merchant in your
+applications.
+
+## Installation
+
+### From Git
+
+You can check out the latest source from git:
+
+ git clone git://github.com/Shopify/active_merchant.git
+
+### As a Rails plugin
+
+ActiveMerchant includes an init.rb file. This means that Rails will automatically load ActiveMerchant on startup. Run
+the following command from the root directory of your Rails project to install ActiveMerchant as a Rails plugin:
+
+ script/plugin install git://github.com/Shopify/active_merchant.git
+
+### From RubyGems
+
+Installation from RubyGems
+
+ gem install activemerchant
+
+Alternatively, add the following to your Gemfile
+
+ gem 'activemerchant', :require => 'active_merchant'
+
+## Usage
+
+This simple example demonstrates how a purchase can be made using a person's
+credit card details.
+
+ require 'rubygems'
+ require 'active_merchant'
+
+ # Use the TrustCommerce test servers
+ ActiveMerchant::Billing::Base.mode = :test
+
+ gateway = ActiveMerchant::Billing::TrustCommerceGateway.new(
+ :login => 'TestMerchant',
+ :password => 'password')
+
+ # ActiveMerchant accepts all amounts as Integer values in cents
+ amount = 1000 # $10.00
+
+ # The card verification value is also known as CVV2, CVC2, or CID
+ credit_card = ActiveMerchant::Billing::CreditCard.new(
+ :first_name => 'Bob',
+ :last_name => 'Bobsen',
+ :number => '4242424242424242',
+ :month => '8',
+ :year => '2012',
+ :verification_value => '123')
+
+ # Validating the card automatically detects the card type
+ if credit_card.valid?
+ # Capture $10 from the credit card
+ response = gateway.purchase(amount, credit_card)
+
+ if response.success?
+ puts "Successfully charged $#{sprintf("%.2f", amount / 100)} to the credit card #{credit_card.display_number}"
+ else
+ raise StandardError, response.message
+ end
+ end
+
+For more in-depth documentation and tutorials, see {file:GettingStarted.md} and the
+[API documentation](http://rubydoc.info/github/Shopify/active_merchant/master/file/README.md).
+
+## Supported Direct Payment Gateways
+
+The [ActiveMerchant Wiki](http://github.com/Shopify/active_merchant/wikis) contains a [table of features supported by each gateway](http://github.com/Shopify/active_merchant/wikis/gatewayfeaturematrix).
+
+* [Authorize.Net CIM](http://www.authorize.net/) - US
+* [Authorize.Net](http://www.authorize.net/) - US
+* [Barclays ePDQ](http://www.barclaycard.co.uk/business/accepting-payments/epdq-mpi/) - UK
+* [Beanstream.com](http://www.beanstream.com/) - CA
+* [BluePay](http://www.bluepay.com/) - US
+* [Braintree](http://www.braintreepaymentsolutions.com) - US
+* [CardStream](http://www.cardstream.com/) - GB
+* [CyberSource](http://www.cybersource.com) - US
+* [DataCash](http://www.datacash.com/) - GB
+* [Efsnet](http://www.concordefsnet.com/) - US
+* [Elavon MyVirtualMerchant](http://www.elavon.com) - US, CA
+* [ePay](http://www.epay.dk/) - DK, SE, NO
+* [eWAY](http://www.eway.com.au/) - AU
+* [E-xact](http://www.e-xact.com) - CA, US
+* [Federated Canada](http://www.federatedcanada.com/) - CA
+* [FirstPay](http://www.first-pay.com) - US
+* [Garanti Sanal POS](https://ccpos.garanti.com.tr/ccRaporlar/garanti/ccReports) - US, TR
+* [Inspire](http://www.inspiregateway.com) - US
+* [InstaPay](http://www.instapayllc.com) - US
+* [Iridium](http://www.iridiumcorp.co.uk/) - UK, ES
+* [JetPay](http://www.jetpay.com) - US
+* [LinkPoint](http://www.linkpoint.com/) - US
+* [Merchant e-Solutions](http://merchante-solutions.com/) - US
+* [MerchantWare](http://merchantwarehouse.com/merchantware) - US
+* [Modern Payments](http://www.modpay.com) - US
+* [Moneris](http://www.moneris.com/) - CA
+* [Netaxept](http://www.betalingsterminal.no/Netthandel-forside) - NO, DK, SE, FI
+* [NetRegistry](http://www.netregistry.com.au) - AU
+* [NELiX TransaX Gateway](http://www.nelixtransax.com) - US
+* [NETbilling](http://www.netbilling.com) - US
+* [NMI](http://nmi.com/) - US
+* [Ogone DirectLink](http://www.ogone.com) - BE, DE, FR, NL, AT, CH
+* [Optimal Payments](http://www.optimalpayments.com/) - CA, US, GB
+* [Orbital Paymentech](http://chasepaymentech.com/) - CA, US
+* [PayBox Direct](http://www.paybox.com) - FR
+* [PayJunction](http://www.payjunction.com/) - US
+* [PaySecure](http://www.commsecure.com.au/paysecure.shtml) - AU
+* [PayPal Express Checkout](https://www.paypal.com/cgi-bin/webscr?cmd=xpt/merchant/ExpressCheckoutIntro-outside) - US, CA, SG, AU
+* [PayPal Payflow Pro](https://www.paypal.com/cgi-bin/webscr?cmd=_payflow-pro-overview-outside) - US, CA, SG, AU
+* [PayPal Website Payments Pro (UK)](https://www.paypal.com/uk/cgi-bin/webscr?cmd=_wp-pro-overview-outside) - GB
+* [PaymentExpress](http://www.paymentexpress.com/) - AU, MY, NZ, SG, ZA, GB, US
+* [PayPal Website Payments Pro (CA)](https://www.paypal.com/cgi-bin/webscr?cmd=_wp-pro-overview-outside) - CA
+* [PayPal Express Checkout](https://www.paypal.com/cgi-bin/webscr?cmd=xpt/merchant/ExpressCheckoutIntro-outside) - US
+* [PayPal Website Payments Pro (US)](https://www.paypal.com/cgi-bin/webscr?cmd=_wp-pro-overview-outside) - US
+* [Plug'n Pay](http://www.plugnpay.com/) - US
+* [Psigate](http://www.psigate.com/) - CA
+* [PSL Payment Solutions](http://www.paymentsolutionsltd.com/) - GB
+* [Quantum](http://www.quantumgateway.com) - US
+* [QuickBooks Merchant Services](http://payments.intuit.com/) - US
+* [Quickpay](http://quickpay.dk/) - DK, SE
+* [Rabobank Nederland](http://www.rabobank.nl/) - NL
+* [Realex](http://www.realexpayments.com/) - IE, GB
+* [SagePay](http://www.sagepay.com) - GB
+* [Sage Payment Solutions](http://www.sagepayments.com) - US, CA
+* [Sallie Mae](http://www.salliemae.com) - US
+* [SecureNet](http://www.securenet.com) - US
+* [SecurePay](http://securepay.com.au) - AU
+* [SecurePay](http://www.securepay.com/) - US
+* [SecurePayTech](http://www.securepaytech.com/) - NZ
+* [SkipJack](http://www.skipjack.com/) - US, CA
+* [Stripe](https://stripe.com/welcome) - US
+* [TransFirst](http://www.transfirst.com/) - US
+* [TrustCommerce](http://www.trustcommerce.com/) - US
+* [USA ePay](http://www.usaepay.com/) - US
+* [Verifi](http://www.verifi.com/) - US
+* [ViaKLIX](http://viaklix.com) - US
+* [Wirecard](http://www.wirecard.com) - DE
+* [WorldPay](http://www.worldpay.com) - AU, HK, GB, US
+
+## Supported Offsite Payment Gateways
+
+* [2 Checkout](http://www.2checkout.com)
+* [Banca Sella GestPay](https://www.sella.it/banca/ecommerce/gestpay/gestpay.jsp)
+* [Chronopay](http://www.chronopay.com)
+* [Direct-eBanking / sofortueberweisung.de by Payment-Networks AG](https://www.payment-network.com/deb_com_en/merchantarea/home) - DE, AT, CH, BE, UK, NL
+* [DirecPay](http://www.timesofmoney.com/direcpay/jsp/home.jsp)
+* [Dwolla](https://www.dwolla.com/default.aspx)
+* [HiTRUST](http://www.hitrust.com.hk/)
+* [Moneybookers](http://www.moneybookers.com)
+* [Nochex](http://www.nochex.com)
+* [PayPal Website Payments Standard](https://www.paypal.com/cgi-bin/webscr?cmd#_wp-standard-overview-outside)
+* [SagePay Form](http://www.sagepay.com/products_services/sage_pay_go/integration/form)
+* [Valitor](http://www.valitor.is/) - IS
+* [WorldPay](http://www.worldpay.com)
+
+## Contributing
+
+The source code is hosted at [GitHub](http://github.com/Shopify/active_merchant), and can be fetched using:
+
+ git clone git://github.com/Shopify/active_merchant.git
+
+Please see the [ActiveMerchant Guide to Contributing](http://github.com/Shopify/active_merchant/wikis/contributing) for
+information on adding a new gateway to ActiveMerchant.
+
+[![Build Status](https://secure.travis-ci.org/Shopify/active_merchant.png)](http://travis-ci.org/Shopify/active_merchant)
9 Rakefile
View
@@ -1,6 +1,13 @@
$:.unshift File.expand_path('../lib', __FILE__)
-require 'rubygems'
+begin
+ require 'bundler'
+ Bundler.setup
+rescue LoadError => e
+ puts "Error loading bundler (#{e.message}): \"gem install bundler\" for bundler support."
+ require 'rubygems'
+end
+
require 'rake'
require 'rake/testtask'
require 'rake/rdoctask'
18 activemerchant.gemspec
View
@@ -1,7 +1,10 @@
+$:.push File.expand_path("../lib", __FILE__)
+require 'active_merchant/version'
+
Gem::Specification.new do |s|
s.platform = Gem::Platform::RUBY
s.name = 'activemerchant'
- s.version = '1.9.0'
+ s.version = ActiveMerchant::VERSION
s.summary = 'Framework and tools for dealing with credit card transactions.'
s.description = 'Active Merchant is a simple payment abstraction library used in and sponsored by Shopify. It is written by Tobias Luetke, Cody Fauser, and contributors. The aim of the project is to feel natural to Ruby users and to abstract as many parts as possible away from the user to offer a consistent interface across all supported gateways.'
@@ -13,12 +16,19 @@ Gem::Specification.new do |s|
s.files = Dir['CHANGELOG', 'README.rdoc', 'MIT-LICENSE', 'CONTRIBUTORS', 'gem-public_cert.pem', 'lib/**/*', 'vendor/**/*']
s.require_path = 'lib'
- s.has_rdoc = true
+ s.has_rdoc = true if Gem::VERSION < '1.7.0'
- s.add_dependency('activesupport', '>= 2.3.2')
+ s.add_dependency('activesupport', '>= 2.3.11')
+ s.add_dependency('i18n')
+ s.add_dependency('money', '<= 3.7.1')
s.add_dependency('builder', '>= 2.0.0')
s.add_dependency('braintree', '>= 2.0.0')
-
+ s.add_dependency('json', '>= 1.5.1') if RUBY_VERSION =~ /^1\.8\./
+ s.add_dependency('active_utils', '>= 1.0.1')
+
+ s.add_development_dependency('rake')
+ s.add_development_dependency('mocha')
+ s.add_development_dependency('rails', '>= 2.3.11')
s.signing_key = ENV['GEM_PRIVATE_KEY']
s.cert_chain = ['gem-public_cert.pem']
end
13 lib/active_merchant.rb
View
@@ -20,30 +20,29 @@
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#++
-
-$:.unshift File.dirname(__FILE__)
require 'active_support'
require 'active_support/core_ext/string/inflections'
require 'active_support/core_ext/hash/indifferent_access'
-require 'active_support/core_ext/class/inheritable_attributes'
+require 'active_support/core_ext/hash/conversions'
+require 'active_support/core_ext/object/conversions'
+require 'active_support/core_ext/class/attribute'
require 'active_support/core_ext/class/attribute_accessors'
require 'active_support/core_ext/class/delegating_attributes'
require 'active_support/core_ext/module/attribute_accessors'
-require 'active_support/core_ext/kernel/requires'
require 'active_support/base64'
-require 'active_support/secure_random'
+require 'securerandom'
require 'builder'
require 'cgi'
require 'rexml/document'
-require 'active_merchant/common'
+require 'active_utils'
require 'active_merchant/billing'
require 'active_merchant/version'
module ActiveMerchant #:nodoc:
- module Billing #:nodoc:
+ module Billing #:nodoc:
autoload :Integrations, 'active_merchant/billing/integrations'
end
end
4 lib/active_merchant/billing/avs_result.rb
View
@@ -53,9 +53,9 @@ class AVSResult
# Map vendor's AVS result code to a street match code
STREET_MATCH_CODE = {
'Y' => %w( A B D H J M O Q T V X Y ),
- 'N' => %w( C K L N P W Z ),
+ 'N' => %w( C K L N W Z ),
'X' => %w( G S ),
- nil => %w( E F I R U )
+ nil => %w( E F I P R U )
}.inject({}) do |map, (type, codes)|
codes.each { |code| map[code] = type }
map
217 lib/active_merchant/billing/credit_card.rb
View
@@ -4,93 +4,183 @@
module ActiveMerchant #:nodoc:
module Billing #:nodoc:
- # == Description
- # This credit card object can be used as a stand alone object. It acts just like an ActiveRecord object
- # but doesn't support the .save method as its not backed by a database.
- #
- # For testing purposes, use the 'bogus' credit card type. This card skips the vast majority of
- # validations. This allows you to focus on your core concerns until you're ready to be more concerned
- # with the details of particular creditcards or your gateway.
- #
+ # A +CreditCard+ object represents a physical credit card, and is capable of validating the various
+ # data associated with these.
+ #
+ # At the moment, the following credit card types are supported:
+ #
+ # * Visa
+ # * MasterCard
+ # * Discover
+ # * American Express
+ # * Diner's Club
+ # * JCB
+ # * Switch
+ # * Solo
+ # * Dankort
+ # * Maestro
+ # * Forbrugsforeningen
+ # * Laser
+ #
+ # For testing purposes, use the 'bogus' credit card type. This skips the vast majority of
+ # validations, allowing you to focus on your core concerns until you're ready to be more concerned
+ # with the details of particular credit cards or your gateway.
+ #
# == Testing With CreditCard
- # Often when testing we don't care about the particulars of a given card type. When using the 'test'
- # mode in your Gateway, there are six different valid card numbers: 1, 2, 3, 'success', 'fail',
+ # Often when testing we don't care about the particulars of a given card type. When using the 'test'
+ # mode in your {Gateway}, there are six different valid card numbers: 1, 2, 3, 'success', 'fail',
# and 'error'.
- #
- #--
- # For details, see CreditCardMethods#valid_number?
- #++
- #
+ #
+ # For details, see {CreditCardMethods::ClassMethods#valid_number?}
+ #
# == Example Usage
# cc = CreditCard.new(
- # :first_name => 'Steve',
- # :last_name => 'Smith',
- # :month => '9',
- # :year => '2010',
- # :type => 'visa',
+ # :first_name => 'Steve',
+ # :last_name => 'Smith',
+ # :month => '9',
+ # :year => '2010',
+ # :type => 'visa',
# :number => '4242424242424242'
# )
- #
+ #
# cc.valid? # => true
# cc.display_number # => XXXX-XXXX-XXXX-4242
#
class CreditCard
include CreditCardMethods
include Validateable
-
- ## Attributes
-
+
cattr_accessor :require_verification_value
self.require_verification_value = true
-
- # Essential attributes for a valid, non-bogus creditcards
- attr_accessor :number, :month, :year, :type, :first_name, :last_name
-
+
+ # Returns or sets the credit card number.
+ #
+ # @return [String]
+ attr_accessor :number
+
+ # Returns or sets the expiry month for the card.
+ #
+ # @return [Integer]
+ attr_accessor :month
+
+ # Returns or sets the expiry year for the card.
+ #
+ # @return [Integer]
+ attr_accessor :year
+
+ # Returns or sets the credit card type.
+ #
+ # Valid card types are
+ #
+ # * +'visa'+
+ # * +'master'+
+ # * +'discover'+
+ # * +'american_express'+
+ # * +'diners_club'+
+ # * +'jcb'+
+ # * +'switch'+
+ # * +'solo'+
+ # * +'dankort'+
+ # * +'maestro'+
+ # * +'forbrugsforeningen'+
+ # * +'laser'+
+ #
+ # Or, if you wish to test your implementation, +'bogus'+.
+ #
+ # @return (String) the credit card type
+ attr_accessor :type
+
+ # Returns or sets the first name of the card holder.
+ #
+ # @return [String]
+ attr_accessor :first_name
+
+ # Returns or sets the last name of the card holder.
+ #
+ # @return [String]
+ attr_accessor :last_name
+
# Required for Switch / Solo cards
attr_accessor :start_month, :start_year, :issue_number
- # Optional verification_value (CVV, CVV2 etc). Gateways will try their best to
- # run validation on the passed in value if it is supplied
+ # Returns or sets the card verification value.
+ #
+ # This attribute is optional but recommended. The verification value is
+ # a {card security code}[http://en.wikipedia.org/wiki/Card_security_code]. If provided,
+ # the gateway will attempt to validate the value.
+ #
+ # @return [String] the verification value
attr_accessor :verification_value
+ alias_method :brand, :type
+
# Provides proxy access to an expiry date object
+ #
+ # @return [ExpiryDate]
def expiry_date
ExpiryDate.new(@month, @year)
end
+ # Returns whether the credit card has expired.
+ #
+ # @return +true+ if the card has expired, +false+ otherwise
def expired?
expiry_date.expired?
end
-
+
+ # Returns whether either the +first_name+ or the +last_name+ attributes has been set.
def name?
- first_name? && last_name?
+ first_name? || last_name?
end
-
+
+ # Returns whether the +first_name+ attribute has been set.
def first_name?
- !@first_name.blank?
+ @first_name.present?
end
-
+
+ # Returns whether the +last_name+ attribute has been set.
def last_name?
- !@last_name.blank?
+ @last_name.present?
end
-
+
+ # Returns the full name of the card holder.
+ #
+ # @return [String] the full name of the card holder
def name
- "#{@first_name} #{@last_name}"
+ [@first_name, @last_name].compact.join(' ')
+ end
+
+ def name=(full_name)
+ names = full_name.split
+ self.last_name = names.pop
+ self.first_name = names.join(" ")
end
-
+
def verification_value?
!@verification_value.blank?
end
- # Show the card number, with all but last 4 numbers replace with "X". (XXXX-XXXX-XXXX-4338)
+ # Returns a display-friendly version of the card number.
+ #
+ # All but the last 4 numbers are replaced with an "X", and hyphens are
+ # inserted in order to improve legibility.
+ #
+ # @example
+ # credit_card = CreditCard.new(:number => "2132542376824338")
+ # credit_card.display_number # "XXXX-XXXX-XXXX-4338"
+ #
+ # @return [String] a display-friendly version of the card number
def display_number
self.class.mask(number)
end
-
+
def last_digits
self.class.last_digits(number)
end
-
+
+ # Validates the credit card details.
+ #
+ # Any validation errors are added to the {#errors} attribute.
def validate
validate_essential_attributes
@@ -102,14 +192,14 @@ def validate
validate_verification_value
validate_switch_or_solo_attributes
end
-
+
def self.requires_verification_value?
require_verification_value
end
-
+
private
-
- def before_validate #:nodoc:
+
+ def before_validate #:nodoc:
self.month = month.to_i
self.year = year.to_i
self.start_month = start_month.to_i unless start_month.nil?
@@ -118,27 +208,38 @@ def before_validate #:nodoc:
self.type.downcase! if type.respond_to?(:downcase)
self.type = self.class.type?(number) if type.blank?
end
-
+
def validate_card_number #:nodoc:
- errors.add :number, "is not a valid credit card number" unless CreditCard.valid_number?(number)
+ if number.blank?
+ errors.add :number, "is required"
+ elsif !CreditCard.valid_number?(number)
+ errors.add :number, "is not a valid credit card number"
+ end
+
unless errors.on(:number) || errors.on(:type)
errors.add :type, "is not the correct card type" unless CreditCard.matching_type?(number, type)
end
end
-
+
def validate_card_type #:nodoc:
- errors.add :type, "is required" if type.blank?
- errors.add :type, "is invalid" unless CreditCard.card_companies.keys.include?(type)
+ errors.add :type, "is required" if type.blank? && number.present?
+ errors.add :type, "is invalid" unless type.blank? || CreditCard.card_companies.keys.include?(type)
end
-
+
def validate_essential_attributes #:nodoc:
errors.add :first_name, "cannot be empty" if @first_name.blank?
errors.add :last_name, "cannot be empty" if @last_name.blank?
- errors.add :month, "is not a valid month" unless valid_month?(@month)
- errors.add :year, "expired" if expired?
- errors.add :year, "is not a valid year" unless valid_expiry_year?(@year)
+
+ if @month.to_i.zero? || @year.to_i.zero?
+ errors.add :month, "is required" if @month.to_i.zero?
+ errors.add :year, "is required" if @year.to_i.zero?
+ else
+ errors.add :month, "is not a valid month" unless valid_month?(@month)
+ errors.add :year, "expired" if expired?
+ errors.add :year, "is not a valid year" unless expired? || valid_expiry_year?(@year)
+ end
end
-
+
def validate_switch_or_solo_attributes #:nodoc:
if %w[switch solo].include?(type)
unless valid_month?(@start_month) && valid_start_year?(@start_year) || valid_issue_number?(@issue_number)
@@ -148,10 +249,10 @@ def validate_switch_or_solo_attributes #:nodoc:
end
end
end
-
+
def validate_verification_value #:nodoc:
if CreditCard.requires_verification_value?
- errors.add :verification_value, "is required" unless verification_value?
+ errors.add :verification_value, "is required" unless verification_value?
end
end
end
6 lib/active_merchant/billing/credit_card_methods.rb
View
@@ -5,11 +5,11 @@ module CreditCardMethods
CARD_COMPANIES = {
'visa' => /^4\d{12}(\d{3})?$/,
'master' => /^(5[1-5]\d{4}|677189)\d{10}$/,
- 'discover' => /^(6011|65\d{2})\d{12}$/,
+ 'discover' => /^(6011|65\d{2}|64[4-9]\d)\d{12}|(62\d{14})$/,
'american_express' => /^3[47]\d{13}$/,
'diners_club' => /^3(0[0-5]|[68]\d)\d{11}$/,
'jcb' => /^35(28|29|[3-8]\d)\d{12}$/,
- 'switch' => /^6759\d{12}(\d{2,3})?$/,
+ 'switch' => /^6759\d{12}(\d{2,3})?$/,
'solo' => /^6767\d{12}(\d{2,3})?$/,
'dankort' => /^5019\d{12}$/,
'maestro' => /^(5[06-8]|6\d)\d{10,17}$/,
@@ -122,4 +122,4 @@ def valid_checksum?(number) #:nodoc:
end
end
end
-end
+end
25 lib/active_merchant/billing/gateway.rb
View
@@ -62,7 +62,9 @@ class Gateway
include Utils
DEBIT_CARDS = [ :switch, :solo ]
-
+ CURRENCIES_WITHOUT_FRACTIONS = [ 'JPY' ]
+ CREDIT_DEPRECATION_MESSAGE = "Support for using credit to refund existing transactions is deprecated and will be removed from a future release of ActiveMerchant. Please use the refund method instead."
+
cattr_reader :implementations
@@implementations = []
@@ -74,22 +76,22 @@ def self.inherited(subclass)
# The format of the amounts used by the gateway
# :dollars => '12.50'
# :cents => '1250'
- class_inheritable_accessor :money_format
+ class_attribute :money_format
self.money_format = :dollars
# The default currency for the transactions if no currency is provided
- class_inheritable_accessor :default_currency
+ class_attribute :default_currency
# The countries of merchants the gateway supports
- class_inheritable_accessor :supported_countries
+ class_attribute :supported_countries
self.supported_countries = []
# The supported card types for the gateway
- class_inheritable_accessor :supported_cardtypes
+ class_attribute :supported_cardtypes
self.supported_cardtypes = []
- class_inheritable_accessor :homepage_url
- class_inheritable_accessor :display_name
+ class_attribute :homepage_url
+ class_attribute :display_name
# The application making the calls to the gateway
# Useful for things like the PayPal build notation (BN) id fields
@@ -133,13 +135,13 @@ def name
def amount(money)
return nil if money.nil?
cents = if money.respond_to?(:cents)
- warn "Support for Money objects is deprecated and will be removed from a future release of ActiveMerchant. Please use an Integer value in cents"
+ deprecated "Support for Money objects is deprecated and will be removed from a future release of ActiveMerchant. Please use an Integer value in cents"
money.cents
else
money
end
- if money.is_a?(String) or cents.to_i < 0
+ if money.is_a?(String)
raise ArgumentError, 'money amount must be a positive Integer in cents.'
end
@@ -149,6 +151,11 @@ def amount(money)
sprintf("%.2f", cents.to_f / 100)
end
end
+
+ def localized_amount(money, currency)
+ amount = amount(money)
+ CURRENCIES_WITHOUT_FRACTIONS.include?(currency.to_s) ? amount.split('.').first : amount
+ end
def currency(money)
money.respond_to?(:currency) ? money.currency : self.default_currency
64 lib/active_merchant/billing/gateways/authorize_net.rb
View
@@ -19,14 +19,14 @@ module Billing #:nodoc:
#
# Automated Recurring Billing (ARB) is an optional service for submitting and managing recurring, or subscription-based, transactions.
#
- # To use recurring, update_recurring, and cancel_recurring ARB must be enabled for your account.
+ # To use recurring, update_recurring, cancel_recurring and status_recurring ARB must be enabled for your account.
#
# Information about ARB is available on the {Authorize.Net website}[http://www.authorize.net/solutions/merchantsolutions/merchantservices/automatedrecurringbilling/].
# Information about the ARB API is available at the {Authorize.Net Integration Center}[http://developer.authorize.net/]
class AuthorizeNetGateway < Gateway
API_VERSION = '3.1'
- class_inheritable_accessor :test_url, :live_url, :arb_test_url, :arb_live_url
+ class_attribute :test_url, :live_url, :arb_test_url, :arb_live_url
self.test_url = "https://test.authorize.net/gateway/transact.dll"
self.live_url = "https://secure.authorize.net/gateway/transact.dll"
@@ -34,7 +34,7 @@ class AuthorizeNetGateway < Gateway
self.arb_test_url = 'https://apitest.authorize.net/xml/v1/request.api'
self.arb_live_url = 'https://api.authorize.net/xml/v1/request.api'
- class_inheritable_accessor :duplicate_window
+ class_attribute :duplicate_window
APPROVED, DECLINED, ERROR, FRAUD_REVIEW = 1, 2, 3, 4
@@ -42,19 +42,21 @@ class AuthorizeNetGateway < Gateway
AVS_RESULT_CODE, TRANSACTION_ID, CARD_CODE_RESPONSE_CODE = 5, 6, 38
self.supported_countries = ['US']
- self.supported_cardtypes = [:visa, :master, :american_express, :discover]
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb]
self.homepage_url = 'http://www.authorize.net/'
self.display_name = 'Authorize.Net'
CARD_CODE_ERRORS = %w( N S )
AVS_ERRORS = %w( A E N R W Z )
+ AVS_REASON_CODES = %w(27 45)
AUTHORIZE_NET_ARB_NAMESPACE = 'AnetApi/xml/v1/schema/AnetApiSchema.xsd'
RECURRING_ACTIONS = {
:create => 'ARBCreateSubscription',
:update => 'ARBUpdateSubscription',
- :cancel => 'ARBCancelSubscription'
+ :cancel => 'ARBCancelSubscription',
+ :status => 'ARBGetSubscriptionStatus'
}
# Creates a new AuthorizeNetGateway
@@ -130,34 +132,49 @@ def capture(money, authorization, options = {})
# * <tt>authorization</tt> - The authorization returned from the previous authorize request.
def void(authorization, options = {})
post = {:trans_id => authorization}
+ add_duplicate_window(post)
commit('VOID', nil, post)
end
- # Credit an account.
+ # Refund a transaction.
#
- # This transaction is also referred to as a Refund and indicates to the gateway that
+ # This transaction indicates to the gateway that
# money should flow from the merchant to the customer.
#
# ==== Parameters
#
# * <tt>money</tt> -- The amount to be credited to the customer as an Integer value in cents.
- # * <tt>identification</tt> -- The ID of the original transaction against which the credit is being issued.
+ # * <tt>identification</tt> -- The ID of the original transaction against which the refund is being issued.
# * <tt>options</tt> -- A hash of parameters.
#
# ==== Options
#
- # * <tt>:card_number</tt> -- The credit card number the credit is being issued to. (REQUIRED)
- def credit(money, identification, options = {})
+ # * <tt>:card_number</tt> -- The credit card number the refund is being issued to. (REQUIRED)
+ # * <tt>:first_name</tt> -- The first name of the account being refunded.
+ # * <tt>:last_name</tt> -- The last name of the account being refunded.
+ # * <tt>:zip</tt> -- The postal code of the account being refunded.
+ def refund(money, identification, options = {})
requires!(options, :card_number)
post = { :trans_id => identification,
:card_num => options[:card_number]
}
+
+ post[:first_name] = options[:first_name] if options[:first_name]
+ post[:last_name] = options[:last_name] if options[:last_name]
+ post[:zip] = options[:zip] if options[:zip]
+
add_invoice(post, options)
+ add_duplicate_window(post)
commit('CREDIT', money, post)
end
+ def credit(money, identification, options = {})
+ deprecated CREDIT_DEPRECATION_MESSAGE
+ refund(money, identification, options)
+ end
+
# Create a recurring payment.
#
# This transaction creates a new Automated Recurring Billing (ARB) subscription. Your account must have ARB enabled.
@@ -226,6 +243,19 @@ def cancel_recurring(subscription_id)
recurring_commit(:cancel, request)
end
+ # Get Subscription Status of a recurring payment.
+ #
+ # This transaction gets the status of an existing Automated Recurring Billing (ARB) subscription. Your account must have ARB enabled.
+ #
+ # ==== Parameters
+ #
+ # * <tt>subscription_id</tt> -- A string containing the +subscription_id+ of the recurring payment already in place
+ # for a given credit card. (REQUIRED)
+ def status_recurring(subscription_id)
+ request = build_recurring_request(:status, :subscription_id => subscription_id)
+ recurring_commit(:status, request)
+ end
+
private
def commit(action, money, parameters)
@@ -290,6 +320,7 @@ def post_data(action, parameters = {})
post[:delim_data] = "TRUE"
post[:delim_char] = ","
post[:encap_char] = "$"
+ post[:solution_ID] = application_id if application_id.present? && application_id != "ActiveMerchant"
request = post.merge(parameters).collect { |key, value| "x_#{key}=#{CGI.escape(value.to_s)}" }.join("&")
request
@@ -370,10 +401,12 @@ def normalize(field)
def message_from(results)
if results[:response_code] == DECLINED
return CVVResult.messages[ results[:card_code] ] if CARD_CODE_ERRORS.include?(results[:card_code])
- return AVSResult.messages[ results[:avs_result_code] ] if AVS_ERRORS.include?(results[:avs_result_code])
+ if AVS_REASON_CODES.include?(results[:response_reason_code]) && AVS_ERRORS.include?(results[:avs_result_code])
+ return AVSResult.messages[ results[:avs_result_code] ]
+ end
end
- return results[:response_reason_text].nil? ? '' : results[:response_reason_text][0..-2]
+ (results[:response_reason_text] ? results[:response_reason_text].chomp('.') : '')
end
def expdate(creditcard)
@@ -437,6 +470,13 @@ def build_arb_cancel_subscription_request(xml, options)
xml.target!
end
+ # Builds body for ARBGetSubscriptionStatusRequest
+ def build_arb_status_subscription_request(xml, options)
+ xml.tag!('subscriptionId', options[:subscription_id])
+
+ xml.target!
+ end
+
# Adds subscription information
def add_arb_subscription(xml, options)
xml.tag!('subscription') do
146 lib/active_merchant/billing/gateways/authorize_net_cim.rb
View
@@ -27,7 +27,7 @@ module Billing #:nodoc:
# 5. Click Submit
class AuthorizeNetCimGateway < Gateway
- class_inheritable_accessor :test_url, :live_url
+ class_attribute :test_url, :live_url
self.test_url = 'https://apitest.authorize.net/xml/v1/request.api'
self.live_url = 'https://api.authorize.net/xml/v1/request.api'
@@ -54,13 +54,17 @@ class AuthorizeNetCimGateway < Gateway
CIM_TRANSACTION_TYPES = {
:auth_capture => 'profileTransAuthCapture',
:auth_only => 'profileTransAuthOnly',
- :capture_only => 'profileTransCaptureOnly'
+ :capture_only => 'profileTransCaptureOnly',
+ :prior_auth_capture => 'profileTransPriorAuthCapture',
+ :refund => 'profileTransRefund',
+ :void => 'profileTransVoid'
}
CIM_VALIDATION_MODES = {
:none => 'none',
:test => 'testMode',
- :live => 'liveMode'
+ :live => 'liveMode',
+ :old => 'oldLiveMode'
}
BANK_ACCOUNT_TYPES = {
@@ -309,14 +313,105 @@ def update_customer_shipping_address(options)
#
# ==== Transaction
#
- # * <tt>:type</tt> -- The type of transaction. Can be either <tt>:auth_only</tt>, <tt>:capture_only</tt>, or <tt>:auth_capture</tt>. (REQUIRED)
- # * <tt>:amount</tt> -- The amount for the tranaction. Formatted with a decimal. For example "4.95" (REQUIRED)
- # * <tt>:customer_profile_id</tt> -- The Customer Profile ID of the customer to use in this transaction. (REQUIRED)
- # * <tt>:customer_payment_profile_id</tt> -- The Customer Payment Profile ID of the Customer Payment Profile to use in this transaction. (REQUIRED)
+ # * <tt>:type</tt> -- The type of transaction. Can be either <tt>:auth_only</tt>, <tt>:capture_only</tt>, <tt>:auth_capture</tt>, <tt>:prior_auth_capture</tt>, <tt>:refund</tt> or <tt>:void</tt>. (REQUIRED)
+ # * <tt>:amount</tt> -- The amount for the tranaction. Formatted with a decimal. For example "4.95" (CONDITIONAL)
+ # - :type == :void (NOT USED)
+ # - :type == (:refund, :auth_only, :capture_only, :auth_capture, :prior_auth_capture) (REQUIRED)
+ #
+ # * <tt>:customer_profile_id</tt> -- The Customer Profile ID of the customer to use in this transaction. (CONDITIONAL)
+ # - :type == (:void, :prior_auth_capture) (OPTIONAL)
+ # - :type == :refund (CONDITIONAL - required if masked information is not being submitted [see below])
+ # - :type == (:auth_only, :capture_only, :auth_capture) (REQUIRED)
+ #
+ # * <tt>:customer_payment_profile_id</tt> -- The Customer Payment Profile ID of the Customer Payment Profile to use in this transaction. (CONDITIONAL)
+ # - :type == (:void, :prior_auth_capture) (OPTIONAL)
+ # - :type == :refund (CONDITIONAL - required if masked information is not being submitted [see below])
+ # - :type == (:auth_only, :capture_only, :auth_capture) (REQUIRED)
+ #
+ # * <tt>:trans_id</tt> -- The payment gateway assigned transaction ID of the original transaction (CONDITIONAL):
+ # - :type = (:void, :refund, :prior_auth_capture) (REQUIRED)
+ # - :type = (:auth_only, :capture_only, :auth_capture) (NOT USED)
+ #
+ # * <tt>customer_shipping_address_id</tt> -- Payment gateway assigned ID associated with the customer shipping address (CONDITIONAL)
+ # - :type = (:void, :refund) (OPTIONAL)
+ # - :type = (:auth_only, :capture_only, :auth_capture) (NOT USED)
+ # - :type = (:prior_auth_capture) (OPTIONAL)
+ #
+ # ==== For :type == :refund only
+ # * <tt>:credit_card_number_masked</tt> -- (CONDITIONAL - requied for credit card refunds is :customer_profile_id AND :customer_payment_profile_id are missing)
+ # * <tt>:bank_routing_number_masked && :bank_account_number_masked</tt> -- (CONDITIONAL - requied for electronic check refunds is :customer_profile_id AND :customer_payment_profile_id are missing) (NOT ABLE TO TEST - I keep getting "ACH transactions are not accepted by this merchant." when trying to make a payment and, until that's possible I can't refund (wiseleyb@gmail.com))
def create_customer_profile_transaction(options)
requires!(options, :transaction)
- requires!(options[:transaction], :type, :amount, :customer_profile_id, :customer_payment_profile_id)
+ requires!(options[:transaction], :type)
+ case options[:transaction][:type]
+ when :void
+ requires!(options[:transaction], :trans_id)
+ when :refund
+ requires!(options[:transaction], :trans_id) &&
+ (
+ (options[:transaction][:customer_profile_id] && options[:transaction][:customer_payment_profile_id]) ||
+ options[:transaction][:credit_card_number_masked] ||
+ (options[:transaction][:bank_routing_number_masked] && options[:transaction][:bank_account_number_masked])
+ )
+ when :prior_auth_capture
+ requires!(options[:transaction], :amount, :trans_id)
+ else
+ requires!(options[:transaction], :amount, :customer_profile_id, :customer_payment_profile_id)
+ end
+ request = build_request(:create_customer_profile_transaction, options)
+ commit(:create_customer_profile_transaction, request)
+ end
+ # Creates a new payment transaction for refund from an existing customer profile
+ #
+ # This is what is used to refund a transaction you have stored in a Customer Profile.
+ #
+ # Returns a Response object that contains the result of the transaction in <tt>params['direct_response']</tt>
+ #
+ # ==== Options
+ #
+ # * <tt>:transaction</tt> -- A hash containing information on the transaction that is being requested. (REQUIRED)
+ #
+ # ==== Transaction
+ #
+ # * <tt>:amount</tt> -- The total amount to be refunded (REQUIRED)
+ #
+ # * <tt>:customer_profile_id</tt> -- The Customer Profile ID of the customer to use in this transaction. (CONDITIONAL :customer_payment_profile_id must be included if used)
+ # * <tt>:customer_payment_profile_id</tt> -- The Customer Payment Profile ID of the Customer Payment Profile to use in this transaction. (CONDITIONAL :customer_profile_id must be included if used)
+ #
+ # * <tt>:credit_card_number_masked</tt> -- Four Xs follwed by the last four digits of the credit card (CONDITIONAL - used if customer_profile_id and customer_payment_profile_id aren't given)
+ #
+ # * <tt>:bank_routing_number_masked</tt> -- The last four gidits of the routing number to be refunded (CONDITIONAL - must be used with :bank_account_number_masked)
+ # * <tt>:bank_account_number_masked</tt> -- The last four digis of the bank account number to be refunded, Ex. XXXX1234 (CONDITIONAL - must be used with :bank_routing_number_masked)
+ def create_customer_profile_transaction_for_refund(options)
+ requires!(options, :transaction)
+ options[:transaction][:type] = :refund
+ requires!(options[:transaction], :trans_id)
+ requires!(options[:transaction], :amount)
+ request = build_request(:create_customer_profile_transaction, options)
+ commit(:create_customer_profile_transaction, request)
+ end
+
+ # Creates a new payment transaction for void from an existing customer profile
+ #
+ # This is what is used to void a transaction you have stored in a Customer Profile.
+ #
+ # Returns a Response object that contains the result of the transaction in <tt>params['direct_response']</tt>
+ #
+ # ==== Options
+ #
+ # * <tt>:transaction</tt> -- A hash containing information on the transaction that is being requested. (REQUIRED)
+ #
+ # ==== Transaction
+ #
+ # * <tt>:trans_id</tt> -- The payment gateway assigned transaction id of the original transaction. (REQUIRED)
+ # * <tt>:customer_profile_id</tt> -- The Customer Profile ID of the customer to use in this transaction.
+ # * <tt>:customer_payment_profile_id</tt> -- The Customer Payment Profile ID of the Customer Payment Profile to use in this transaction.
+ # * <tt>:customer_shipping_address_id</tt> -- Payment gateway assigned ID associated with the customer shipping address.
+ def create_customer_profile_transaction_for_void(options)
+ requires!(options, :transaction)
+ options[:transaction][:type] = :void
+ requires!(options[:transaction], :trans_id)
request = build_request(:create_customer_profile_transaction, options)
commit(:create_customer_profile_transaction, request)
end
@@ -443,6 +538,8 @@ def build_update_customer_payment_profile_request(xml, options)
add_payment_profile(xml, options[:payment_profile])
end
+ xml.tag!('validationMode', CIM_VALIDATION_MODES[options[:validation_mode]]) if options[:validation_mode]
+
xml.target!
end
@@ -502,10 +599,31 @@ def add_transaction(xml, transaction)
xml.tag!('transaction') do
xml.tag!(CIM_TRANSACTION_TYPES[transaction[:type]]) do
# The amount to be billed to the customer
- xml.tag!('amount', transaction[:amount])
- xml.tag!('customerProfileId', transaction[:customer_profile_id])
- xml.tag!('customerPaymentProfileId', transaction[:customer_payment_profile_id])
- xml.tag!('approvalCode', transaction[:approval_code]) if transaction[:type] == :capture_only
+ case transaction[:type]
+ when :void
+ tag_unless_blank(xml,'customerProfileId', transaction[:customer_profile_id])
+ tag_unless_blank(xml,'customerPaymentProfileId', transaction[:customer_payment_profile_id])
+ tag_unless_blank(xml,'customerShippingAddressId', transaction[:customer_shipping_address_id])
+ xml.tag!('transId', transaction[:trans_id])
+ when :refund
+ #TODO - add support for all the other options fields
+ xml.tag!('amount', transaction[:amount])
+ tag_unless_blank(xml, 'customerProfileId', transaction[:customer_profile_id])
+ tag_unless_blank(xml, 'customerPaymentProfileId', transaction[:customer_payment_profile_id])
+ tag_unless_blank(xml, 'customerShippingAddressId', transaction[:customer_shipping_address_id])
+ tag_unless_blank(xml, 'creditCardNumberMasked', transaction[:credit_card_number_masked])
+ tag_unless_blank(xml, 'bankRoutingNumberMasked', transaction[:bank_routing_number_masked])
+ tag_unless_blank(xml, 'bankAccountNumberMasked', transaction[:bank_account_number_masked])
+ xml.tag!('transId', transaction[:trans_id])
+ when :prior_auth_capture
+ xml.tag!('amount', transaction[:amount])
+ xml.tag!('transId', transaction[:trans_id])
+ else
+ xml.tag!('amount', transaction[:amount])
+ xml.tag!('customerProfileId', transaction[:customer_profile_id])
+ xml.tag!('customerPaymentProfileId', transaction[:customer_payment_profile_id])
+ xml.tag!('approvalCode', transaction[:approval_code]) if transaction[:type] == :capture_only
+ end
add_order(xml, transaction[:order]) if transaction[:order]
end
end
@@ -648,6 +766,10 @@ def commit(action, request)
response
end
+ def tag_unless_blank(xml, tag_name, data)
+ xml.tag!(tag_name, data) unless data.blank? || data.nil?
+ end
+
def parse_direct_response(response)
direct_response = {'raw' => response.params['direct_response']}
direct_response_fields = response.params['direct_response'].split(',')
308 lib/active_merchant/billing/gateways/barclays_epdq.rb
View
@@ -0,0 +1,308 @@
+module ActiveMerchant #:nodoc:
+ module Billing #:nodoc:
+ class BarclaysEpdqGateway < Gateway
+ TEST_URL = 'https://secure2.mde.epdq.co.uk:11500'
+ LIVE_URL = 'https://secure2.epdq.co.uk:11500'
+
+ self.supported_countries = ['UK']
+ self.default_currency = 'GBP'
+ self.supported_cardtypes = [:visa, :master, :maestro, :switch ]
+ self.money_format = :cents
+ self.homepage_url = 'http://www.barclaycard.co.uk/business/accepting-payments/epdq-mpi/'
+ self.display_name = 'Barclays ePDQ'
+
+ def initialize(options = {})
+ requires!(options, :login, :password, :client_id)
+ @options = options
+ super
+ end
+
+ def authorize(money, creditcard, options = {})
+ document = Document.new(self, @options) do
+ add_order_form(options[:order_id]) do
+ add_consumer(options) do
+ add_creditcard(creditcard)
+ end
+ add_transaction(:PreAuth, money)
+ end
+ end
+
+ commit(document)
+ end
+
+ def purchase(money, creditcard, options = {})
+ # disable fraud checks if this is a repeat order:
+ if options[:payment_number] && (options[:payment_number] > 1)
+ no_fraud = true
+ else
+ no_fraud = options[:no_fraud]
+ end
+ document = Document.new(self, @options, :no_fraud => no_fraud) do
+ add_order_form(options[:order_id], options[:group_id]) do
+ add_consumer(options) do
+ add_creditcard(creditcard)
+ end
+ add_transaction(:Auth, money, options)
+ end
+ end
+ commit(document)
+ end
+
+ # authorization is your unique order ID, not the authorization
+ # code returned by ePDQ
+ def capture(money, authorization, options = {})
+ document = Document.new(self, @options) do
+ add_order_form(authorization) do
+ add_transaction(:PostAuth, money)
+ end
+ end
+
+ commit(document)
+ end
+
+ # authorization is your unique order ID, not the authorization
+ # code returned by ePDQ
+ def credit(money, creditcard_or_authorization, options = {})
+ if creditcard_or_authorization.is_a?(String)
+ deprecated CREDIT_DEPRECATION_MESSAGE
+ refund(money, creditcard_or_authorization, options)
+ else
+ credit_new_order(money, creditcard_or_authorization, options)
+ end
+ end
+
+ def refund(money, authorization, options = {})
+ credit_existing_order(money, authorization, options)
+ end
+
+ def void(authorization, options = {})
+ document = Document.new(self, @options) do
+ add_order_form(authorization) do
+ add_transaction(:Void)
+ end
+ end
+
+ commit(document)
+ end
+
+ private
+ def credit_new_order(money, creditcard, options)
+ document = Document.new(self, @options) do
+ add_order_form do
+ add_consumer(options) do
+ add_creditcard(creditcard)
+ end
+ add_transaction(:Credit, money)
+ end
+ end
+
+ commit(document)
+ end
+
+ def credit_existing_order(money, authorization, options)
+ order_id, _ = authorization.split(":")
+ document = Document.new(self, @options) do
+ add_order_form(order_id) do
+ add_transaction(:Credit, money)
+ end
+ end
+
+ commit(document)
+ end
+
+ def parse(body)
+ parser = Parser.new(body)
+ response = parser.parse
+ Response.new(response[:success], response[:message], response,
+ :test => test?,
+ :authorization => response[:authorization],
+ :avs_result => response[:avsresponse],
+ :cvv_result => response[:cvv_result],
+ :order_id => response[:order_id],
+ :raw_response => response[:raw_response]
+ )
+ end
+
+ def commit(document)
+ url = (test? ? TEST_URL : LIVE_URL)
+ data = ssl_post(url, document.to_xml)
+ parse(data)
+ end
+
+ class Parser
+ def initialize(response)
+ @response = response
+ end
+
+ def parse
+ doc = REXML::Document.new(@response)
+ auth_type = find(doc, "//Transaction/Type").to_s
+
+ message = find(doc, "//Message/Text")
+ if message.blank?
+ message = find(doc, "//Transaction/CardProcResp/CcReturnMsg")
+ end
+
+ case auth_type
+ when 'Credit', 'Void'
+ success = find(doc, "//CcReturnMsg") == "Approved."
+ else
+ success = find(doc, "//Transaction/AuthCode").present?
+ end
+
+ {
+ :success => success,
+ :message => message,
+ :authorization => find(doc, "//Transaction/Id"),
+ :avs_result => find(doc, "//Transaction/AvsRespCode"),
+ :cvv_result => find(doc, "//Transaction/Cvv2Resp"),
+ :order_id => find(doc, "//OrderFormDoc/Transaction/Id"),
+ :raw_response => @response
+ }
+ end
+
+ def find(doc, xpath)
+ REXML::XPath.first(doc, xpath).try(:text)
+ end
+ end
+
+ class Document
+ attr_reader :type, :xml
+
+ PAYMENT_INTERVALS = {
+ :days => 'D',
+ :months => 'M'
+ }
+
+ EPDQ_CARD_TYPES = {
+ :visa => 1,
+ :master => 2,
+ :switch => 9,
+ :maestro => 10,
+ }
+
+ def initialize(gateway, options = {}, document_options = {}, &block)
+ @gateway = gateway
+ @options = options
+ @document_options = document_options
+ @xml = Builder::XmlMarkup.new(:indent => 2)
+ build(&block)
+ end
+
+ def to_xml
+ @xml.target!
+ end
+
+ def build(&block)
+ xml.instruct!(:xml, :version => '1.0')
+ xml.EngineDocList do
+ xml.DocVersion "1.0"
+ xml.EngineDoc do
+ xml.ContentType "OrderFormDoc"
+ xml.User do
+ xml.Name(@options[:login])
+ xml.Password(@options[:password])
+ xml.ClientId({ :DataType => "S32" }, @options[:client_id])
+ end
+ xml.Instructions do
+ if @document_options[:no_fraud]
+ xml.Pipeline "PaymentNoFraud"
+ else
+ xml.Pipeline "Payment"
+ end
+ end
+ instance_eval(&block)
+ end
+ end
+ end
+
+ def add_order_form(order_id=nil, group_id=nil, &block)
+ xml.OrderFormDoc do
+ xml.Mode 'P'
+ xml.Id(order_id) if order_id
+ xml.GroupId(group_id) if group_id
+ instance_eval(&block)
+ end
+ end
+
+ def add_consumer(options=nil, &block)
+ xml.Consumer do
+ if options
+ xml.Email(options[:email]) if options[:email]
+ billing_address = options[:billing_address] || options[:address]
+ if billing_address
+ xml.BillTo do
+ xml.Location do
+ xml.Address do
+ xml.Street1 billing_address[:address1]
+ xml.Street2 billing_address[:address2]
+ xml.City billing_address[:city]
+ xml.StateProv billing_address[:state]
+ xml.PostalCode billing_address[:zip]
+ xml.Country billing_address[:country_code]
+ end
+ end
+ end
+ end
+ end
+ instance_eval(&block)
+ end
+ end
+
+ def add_creditcard(creditcard)
+ xml.PaymentMech do
+ xml.CreditCard do
+ xml.Type({ :DataType => 'S32' }, EPDQ_CARD_TYPES[creditcard.brand.to_sym])
+ xml.Number creditcard.number
+ xml.Expires({ :DataType => 'ExpirationDate', :Locale => 826 }, format_expiry_date(creditcard))
+ if creditcard.verification_value.present?
+ xml.Cvv2Indicator 1
+ xml.Cvv2Val creditcard.verification_value
+ else
+ xml.Cvv2Indicator 5
+ end
+ xml.IssueNum(creditcard.issue_number) if creditcard.issue_number.present?
+ end
+ end
+ end
+
+ def add_transaction(auth_type, amount = nil, options = {})
+ @auth_type = auth_type
+ xml.Transaction do
+ xml.Type @auth_type.to_s
+ if options[:payment_number] && options[:payment_number] > 1
+ xml.CardholderPresentCode({ :DataType => 'S32' }, 8)
+ else
+ xml.CardholderPresentCode({ :DataType => 'S32' }, 7)
+ end
+ if options[:payment_number]
+ xml.PaymentNumber({ :DataType => 'S32' }, options[:payment_number])
+ end
+ if options[:total_payments]
+ xml.TotalNumberPayments({ :DataType => 'S32' }, options[:total_payments])
+ end
+ if amount
+ xml.CurrentTotals do
+ xml.Totals do
+ xml.Total({ :DataType => 'Money', :Currency => 826 }, amount)
+ end
+ end
+ end
+ end
+ end
+
+ # date must be formatted MM/YY
+ def format_expiry_date(creditcard)
+ month_str = "%02d" % creditcard.month
+ if match = creditcard.year.to_s.match(/^\d{2}(\d{2})$/)
+ year_str = "%02d" % match[1].to_i
+ else
+ year_str = "%02d" % creditcard.year
+ end
+ "#{month_str}/#{year_str}"
+ end
+ end
+ end
+ end
+end
+
41 lib/active_merchant/billing/gateways/beanstream.rb
View
@@ -12,12 +12,19 @@ module Billing #:nodoc:
# * +PA+ - Pre Authorization
# * +PAC+ - Pre Authorization Completion
#
+ # == Secure Payment Profiles:
+ # BeanStream supports payment profiles (vaults). This allows you to store cc information with BeanStream and process subsequent transactions with a customer id.
+ # Secure Payment Profiles must be enabled on your account (must be done over the phone).
+ # Your API Access Passcode must be set in Administration => account settings => order settings.
+ # To learn more about storing credit cards with the Beanstream gateway, please read the BEAN_Payment_Profiles.pdf (I had to phone BeanStream to request it.)
+ #
# == Notes
# * Recurring billing is not yet implemented.
# * Adding of order products information is not implemented.
# * Ensure that country and province data is provided as a code such as "CA", "US", "QC".
# * login is the Beanstream merchant ID, username and password should be enabled in your Beanstream account and passed in using the <tt>:user</tt> and <tt>:password</tt> options.
# * Test your app with your true merchant id and test credit card information provided in the api pdf document.
+ # * Beanstream does not allow Payment Profiles to be deleted with their API. The accounts are 'closed', but have to be deleted manually.
#
# Example authorization (Beanstream PA transaction type):
#
@@ -58,11 +65,11 @@ module Billing #:nodoc:
class BeanstreamGateway < Gateway
include BeanstreamCore
- def authorize(money, credit_card, options = {})
+ def authorize(money, source, options = {})
post = {}
add_amount(post, money)
add_invoice(post, options)
- add_credit_card(post, credit_card)
+ add_source(post, source)
add_address(post, options)
add_transaction_type(post, :authorization)
commit(post)
@@ -91,6 +98,36 @@ def void(authorization, options = {})
def interac
@interac ||= BeanstreamInteracGateway.new(@options)
end
+
+ # To match the other stored-value gateways, like TrustCommerce,
+ # store and unstore need to be defined
+ def store(credit_card, options = {})
+ post = {}
+ add_address(post, options)
+ add_credit_card(post, credit_card)
+ add_secure_profile_variables(post,options)
+ commit(post, true)
+ end
+
+ #can't actually delete a secure profile with the supplicaed API. This function sets the status of the profile to closed (C).
+ #Closed profiles will have to removed manually.
+ def delete(vault_id)
+ update(vault_id, false, {:status => "C"})
+ end
+
+ alias_method :unstore, :delete
+
+ # Update the values (such as CC expiration) stored at
+ # the gateway. The CC number must be supplied in the
+ # CreditCard object.
+ def update(vault_id, credit_card, options = {})
+ post = {}
+ add_address(post, options)
+ add_credit_card(post, credit_card)
+ options.merge!({:vault_id => vault_id, :operation => secure_profile_action(:modify)})
+ add_secure_profile_variables(post,options)
+ commit(post, true)
+ end
private
def build_response(*args)
94 lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb
View
@@ -2,17 +2,24 @@ module ActiveMerchant #:nodoc:
module Billing #:nodoc:
module BeanstreamCore
URL = 'https://www.beanstream.com/scripts/process_transaction.asp'
+ SECURE_PROFILE_URL = 'https://www.beanstream.com/scripts/payment_profile.asp'
+ SP_SERVICE_VERSION = '1.1'
TRANSACTIONS = {
:authorization => 'PA',
:purchase => 'P',
:capture => 'PAC',
- :credit => 'R',
+ :refund => 'R',
:void => 'VP',
:check_purchase => 'D',
- :check_credit => 'C',
+ :check_refund => 'C',
:void_purchase => 'VP',
- :void_credit => 'VR'
+ :void_refund => 'VR'
+ }
+
+ PROFILE_OPERATIONS = {
+ :new => 'N',
+ :modify => 'M'
}
CVD_CODES = {
@@ -48,7 +55,7 @@ def self.included(base)
# Only <tt>:login</tt> is required by default,
# which is the merchant's merchant ID. If you'd like to perform void,
- # capture or credit transactions then you'll also need to add a username
+ # capture or refund transactions then you'll also need to add a username
# and password to your account under administration -> account settings ->
# order settings -> Use username/password validation
def initialize(options = {})
@@ -67,26 +74,39 @@ def capture(money, authorization, options = {})
commit(post)
end
- def credit(money, source, options = {})
+ def refund(money, source, options = {})
post = {}
reference, amount, type = split_auth(source)
add_reference(post, reference)
- add_transaction_type(post, credit_action(type))
+ add_transaction_type(post, refund_action(type))
add_amount(post, money)
commit(post)
end
+
+ def credit(money, source, options = {})
+ deprecated Gateway::CREDIT_DEPRECATION_MESSAGE
+ refund(money, source, options)
+ end