activemerchant 1.21.0 → 1.22.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data.tar.gz.sig +0 -0
  2. data/CHANGELOG +63 -0
  3. data/CONTRIBUTORS +29 -0
  4. data/README.md +195 -0
  5. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +2 -0
  6. data/lib/active_merchant/billing/gateways/barclays_epdq.rb +2 -2
  7. data/lib/active_merchant/billing/gateways/blue_pay.rb +492 -11
  8. data/lib/active_merchant/billing/gateways/braintree_blue.rb +46 -19
  9. data/lib/active_merchant/billing/gateways/certo_direct.rb +1 -1
  10. data/lib/active_merchant/billing/gateways/cyber_source.rb +342 -106
  11. data/lib/active_merchant/billing/gateways/elavon.rb +2 -0
  12. data/lib/active_merchant/billing/gateways/epay.rb +3 -1
  13. data/lib/active_merchant/billing/gateways/itransact.rb +450 -0
  14. data/lib/active_merchant/billing/gateways/migs.rb +259 -0
  15. data/lib/active_merchant/billing/gateways/migs/migs_codes.rb +100 -0
  16. data/lib/active_merchant/billing/gateways/moneris_us.rb +211 -0
  17. data/lib/active_merchant/billing/gateways/ogone.rb +104 -12
  18. data/lib/active_merchant/billing/gateways/orbital.rb +15 -6
  19. data/lib/active_merchant/billing/gateways/paybox_direct.rb +1 -4
  20. data/lib/active_merchant/billing/gateways/payflow.rb +8 -3
  21. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +4 -1
  22. data/lib/active_merchant/billing/gateways/payflow_express.rb +4 -2
  23. data/lib/active_merchant/billing/gateways/payment_express.rb +1 -1
  24. data/lib/active_merchant/billing/gateways/paypal.rb +3 -18
  25. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +287 -1
  26. data/lib/active_merchant/billing/gateways/paypal/paypal_recurring_api.rb +245 -0
  27. data/lib/active_merchant/billing/gateways/paypal_express.rb +14 -66
  28. data/lib/active_merchant/billing/gateways/realex.rb +5 -7
  29. data/lib/active_merchant/billing/gateways/stripe.rb +1 -9
  30. data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +2 -2
  31. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +1 -5
  32. data/lib/active_merchant/billing/gateways/viaklix.rb +7 -2
  33. data/lib/active_merchant/billing/gateways/vindicia.rb +359 -0
  34. data/lib/active_merchant/billing/integrations/dotpay.rb +22 -0
  35. data/lib/active_merchant/billing/integrations/dotpay/helper.rb +77 -0
  36. data/lib/active_merchant/billing/integrations/dotpay/notification.rb +86 -0
  37. data/lib/active_merchant/billing/integrations/dotpay/return.rb +11 -0
  38. data/lib/active_merchant/billing/integrations/epay.rb +21 -0
  39. data/lib/active_merchant/billing/integrations/epay/helper.rb +55 -0
  40. data/lib/active_merchant/billing/integrations/epay/notification.rb +110 -0
  41. data/lib/active_merchant/billing/integrations/paypal/notification.rb +2 -1
  42. data/lib/active_merchant/billing/integrations/quickpay/helper.rb +2 -3
  43. data/lib/active_merchant/billing/integrations/robokassa.rb +49 -0
  44. data/lib/active_merchant/billing/integrations/robokassa/common.rb +19 -0
  45. data/lib/active_merchant/billing/integrations/robokassa/helper.rb +50 -0
  46. data/lib/active_merchant/billing/integrations/robokassa/notification.rb +55 -0
  47. data/lib/active_merchant/billing/integrations/robokassa/return.rb +17 -0
  48. data/lib/active_merchant/billing/integrations/two_checkout.rb +25 -3
  49. data/lib/active_merchant/billing/integrations/two_checkout/helper.rb +15 -0
  50. data/lib/active_merchant/billing/integrations/verkkomaksut.rb +20 -0
  51. data/lib/active_merchant/billing/integrations/verkkomaksut/helper.rb +87 -0
  52. data/lib/active_merchant/billing/integrations/verkkomaksut/notification.rb +59 -0
  53. data/lib/active_merchant/version.rb +1 -1
  54. metadata +59 -26
  55. metadata.gz.sig +0 -0
data.tar.gz.sig CHANGED
Binary file
data/CHANGELOG CHANGED
@@ -1,5 +1,61 @@
1
1
  = ActiveMerchant CHANGELOG
2
2
 
3
+ == Version 1.22.0 (May 17, 2012)
4
+
5
+ * Remove version restriction for money gem [ylansegal]
6
+ * Add iTransact XML gateway [motske]
7
+ * PayPal Express Gateway: add options[:landing_page] [markus]
8
+ * USA ePay: Fix handling of AVS [duff]
9
+ * Ogone: Add store method to create an alias without making a purchase [joelcogen]
10
+ * Spelling fix: purcahse -> purchase [mnoack]
11
+ * ePay: Added more useful results for authorization errors [Dennis O'Connor]
12
+ * Add Robokassa integration [nashby]
13
+ * PayPal Gateway: Add recurring API [dscataglini]
14
+ * Braintree: Add support for :verify_card option on store [brentmc79]
15
+ * Moneris: cannot void a preauthorization [eddanger]
16
+ * Add Moneris US gateway [eddanger]
17
+ * Add Dotpay integration [kacperix]
18
+ * Payflow: Add description, comment and comment2 tags [ksnyder]
19
+ * Dotpay: Fix field mapping [kacperix]
20
+ * Authorize.Net CIM: Optionally add 'order' details to transactions [pote]
21
+ * Braintree: Allow including billing address when storing a customer [brentmc79]
22
+ * PayPal Gateway: Refactored PaymentDetails & PaymentDetailsItem common code [dscataglini]
23
+ * Viaklix/Elavon: Separate "demo accounts" from "test transactions" [mltsy]
24
+ * PayPal Gateway: Add transaction_details, balance, authorize_transaction, and manage_pending_transaction API calls [dscataglini]
25
+ * PayPal Gateway: Add support for TransactionSearch & DoReferenceTransaction [dscataglini]
26
+ * Cybersource: Add recurring payment support [jaredmoory]
27
+ * Tidy up gateway lists [ashokak]
28
+ * Paybox: remove Iconv usage [ntalbott]
29
+ * Dotpay: Add amount mapping, pin setter, and support for test? [kacperix]
30
+ * Braintree Blue: Make address country map to alpha2 [ntalbott]
31
+ * Use GB as the alpha2 country code for the UK [ntalbott]
32
+ * Realex: Handle XML response with unescaped ampersand [ntalbott]
33
+ * Add Vindicia gateway [steved555]
34
+ * Payment Express: use %w[] for country list [parndt]
35
+ * Braintree Blue: Match remote test up with change to :country [braintreeps]
36
+ * PayPal Integration: Fix received_at method time parsing [subbarao]
37
+ * Add MiGS Gateway [mnoack, nagash]
38
+ * Quickpay integration: Fix payment_service_for helper [TheMaster]
39
+ * Braintree Blue gateway: Improve update method [brentmc79]
40
+ * 2checkout integration: Add mode mapping & line items helper [AlexanderZaytsev]
41
+ * USA ePay Advanced gateway: Fix expiration date format. [cctalbott]
42
+ * Add ePay integration [ePay]
43
+ * 2checkout integration: Add support for single page payment routine [AlexanderZaytsev]
44
+ * Ogone: Add support for 3D Secure [rymai, ZenCocoon]
45
+ * Stripe gateway: Remove authorize and capture methods since they are not supported [jduff]
46
+ * Stripe gateway: default test to false if no livemode parameter is specified [jduff]
47
+ * Paybox Direct gateway: 'card absent' and 'do not honour' should be considered failures, not fraudulent [jduff]
48
+ * Add Verkkomaksut integration [akonan]
49
+ * Remove trailing spaces from generator templates [akonan]
50
+ * Payflow gateway: Allow modification of RetryNumDays [jrust]
51
+ * Payflow gateway: Don't auto-set start_date on modification [jrust]
52
+ * Bluepay gateway: Add ACH & recurring support [jslingerland]
53
+ * Orbital gateway: Don't send AVS address details for any country besides US, CA, GB and UK [Soleone]
54
+ * Payflow Express gateway: Better amount handling [jduff]
55
+ * Barclays gateway: Allow American Express [duff]
56
+ * Ogone gateway: Remove duplicated method [ntalbott]
57
+ * Cybersource gateway: Add retrieve method to pull details on a stored card [fabiokr]
58
+
3
59
  == Version 1.21.0 (March 7, 2012)
4
60
 
5
61
  * Stripe: Add support for passing IP [collision]
@@ -28,6 +84,13 @@
28
84
  * Viaklix: Add discover as a supported card type [waelchatila]
29
85
  * Improvements to testing infrastructure for integrations [jduff]
30
86
  * Add NAB Transact (AU) Gateway [tommeier]
87
+ * PayPal Express: Add Support for Reference Transactions using BAIDs [kenmazaika]
88
+ * Authorize.Net CIM: Add support for optional refund fields [nilmethod]
89
+ * SecurePayTech: Fix EnableCSC parameter so CVV codes are checked. [tlconnor]
90
+ * SecurePayTech: Add remote tests for CSC checking. [tlconnor]
91
+ * Samurai: Add option to retain payment methods once stored [brentmc79]
92
+ * PayPal Express Gateway: Add support for Digital Goods / Micropayments [kenmazaika]
93
+
31
94
 
32
95
  == Version 1.20.4 (February 22, 2012)
33
96
 
@@ -272,3 +272,32 @@ Authorize.Net SIM Integration (February, 2012)
272
272
  NAB Transact (AU) Gateway (February, 2012)
273
273
 
274
274
  * Tom Meier (tommeier)
275
+
276
+ iTransact XML Gateway (March, 2012)
277
+
278
+ * Kevin Motschiedler (motske)
279
+
280
+ Robokassa Integration (March, 2012)
281
+
282
+ * Vasiliy Ermolovich (nashby)
283
+
284
+ Moneris US Gateway (March, 2012)
285
+
286
+ * Michael Wood (eddanger)
287
+
288
+ Dotpay Integration (March, 2012)
289
+
290
+ * Przemysław Ciąćka (kacperix)
291
+
292
+ Vindicia gateway (April 2012)
293
+
294
+ * Steven Davidovitz (steved555)
295
+
296
+ MiGS gateway (April 2012)
297
+
298
+ * Michael Noack (mnoack)
299
+ * Justin Jones (nagash)
300
+
301
+ ePay integration (April 2012)
302
+
303
+ * Michael (ePay)
@@ -0,0 +1,195 @@
1
+ # Active Merchant
2
+
3
+ Active Merchant is an extraction from the e-commerce system [Shopify](http://www.shopify.com).
4
+ Shopify's requirements for a simple and unified API to access dozens of different payment
5
+ gateways with very different internal APIs was the chief principle in designing the library.
6
+
7
+ Active Merchant has been in production use since June 2006 and is now used in most modern
8
+ Ruby applications which deal with financial transactions.
9
+
10
+ It was developed for usage in Ruby on Rails web applications and integrates seamlessly
11
+ as a plugin but it also works excellently as a stand alone library.
12
+
13
+ See {file:GettingStarted.md} if you want to learn more about using Active Merchant in your
14
+ applications.
15
+
16
+ ## Installation
17
+
18
+ ### From Git
19
+
20
+ You can check out the latest source from git:
21
+
22
+ git clone git://github.com/Shopify/active_merchant.git
23
+
24
+ ### As a Rails plugin
25
+
26
+ ActiveMerchant includes an init.rb file. This means that Rails will automatically load ActiveMerchant on startup. Run
27
+ the following command from the root directory of your Rails project to install ActiveMerchant as a Rails plugin:
28
+
29
+ script/plugin install git://github.com/Shopify/active_merchant.git
30
+
31
+ ### From RubyGems
32
+
33
+ Installation from RubyGems
34
+
35
+ gem install activemerchant
36
+
37
+ Alternatively, add the following to your Gemfile
38
+
39
+ gem 'activemerchant', :require => 'active_merchant'
40
+
41
+ ## Usage
42
+
43
+ This simple example demonstrates how a purchase can be made using a person's
44
+ credit card details.
45
+
46
+ require 'rubygems'
47
+ require 'active_merchant'
48
+
49
+ # Use the TrustCommerce test servers
50
+ ActiveMerchant::Billing::Base.mode = :test
51
+
52
+ gateway = ActiveMerchant::Billing::TrustCommerceGateway.new(
53
+ :login => 'TestMerchant',
54
+ :password => 'password')
55
+
56
+ # ActiveMerchant accepts all amounts as Integer values in cents
57
+ amount = 1000 # $10.00
58
+
59
+ # The card verification value is also known as CVV2, CVC2, or CID
60
+ credit_card = ActiveMerchant::Billing::CreditCard.new(
61
+ :first_name => 'Bob',
62
+ :last_name => 'Bobsen',
63
+ :number => '4242424242424242',
64
+ :month => '8',
65
+ :year => '2012',
66
+ :verification_value => '123')
67
+
68
+ # Validating the card automatically detects the card type
69
+ if credit_card.valid?
70
+ # Capture $10 from the credit card
71
+ response = gateway.purchase(amount, credit_card)
72
+
73
+ if response.success?
74
+ puts "Successfully charged $#{sprintf("%.2f", amount / 100)} to the credit card #{credit_card.display_number}"
75
+ else
76
+ raise StandardError, response.message
77
+ end
78
+ end
79
+
80
+ For more in-depth documentation and tutorials, see {file:GettingStarted.md} and the
81
+ [API documentation](http://rubydoc.info/github/Shopify/active_merchant/master/file/README.md).
82
+
83
+ ## Supported Direct Payment Gateways
84
+
85
+ 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).
86
+
87
+ * [Authorize.Net](http://www.authorize.net/) - US
88
+ * [Authorize.Net CIM](http://www.authorize.net/) - US
89
+ * [Barclays ePDQ](http://www.barclaycard.co.uk/business/accepting-payments/epdq-mpi/) - UK
90
+ * [Beanstream.com](http://www.beanstream.com/) - CA
91
+ * [BluePay](http://www.bluepay.com/) - US
92
+ * [Braintree](http://www.braintreepaymentsolutions.com) - US
93
+ * [CardStream](http://www.cardstream.com/) - UK
94
+ * [CertoDirect](http://www.certodirect.com/) - BE, BG, CZ, DK, DE, EE, IE, EL, ES, FR, IT, CY, LV, LT, LU, HU, MT, NL, AT, PL, PT, RO, SI, SK, FI, SE, UK
95
+ * [CyberSource](http://www.cybersource.com) - US
96
+ * [DataCash](http://www.datacash.com/) - UK
97
+ * [Efsnet](http://www.concordefsnet.com/) - US
98
+ * [Elavon MyVirtualMerchant](http://www.elavon.com) - US, CA
99
+ * [ePay](http://www.epay.dk/) - DK, SE, NO
100
+ * [eWAY](http://www.eway.com.au/) - AU
101
+ * [E-xact](http://www.e-xact.com) - CA, US
102
+ * [Federated Canada](http://www.federatedcanada.com/) - CA
103
+ * [FirstPay](http://www.first-pay.com) - US
104
+ * [Garanti Sanal POS](https://ccpos.garanti.com.tr/ccRaporlar/garanti/ccReports) - US, TR
105
+ * [Inspire](http://www.inspiregateway.com) - US
106
+ * [InstaPay](http://www.instapayllc.com) - US
107
+ * [Iridium](http://www.iridiumcorp.co.uk/) - UK, ES
108
+ * [iTransact](http://www.itransact.com/) - US
109
+ * [JetPay](http://www.jetpay.com) - US
110
+ * [LinkPoint](http://www.linkpoint.com/) - US
111
+ * [Merchant e-Solutions](http://merchante-solutions.com/) - US
112
+ * [MerchantWare](http://merchantwarehouse.com/merchantware) - US
113
+ * [MasterCard Internet Gateway Service (MiGS)](http://mastercard.com/mastercardsps) - AU, AE, BD, BN, EG, HK, ID, IN, JO, KW, LB, LK, MU, MV, MY, NZ, OM, PH, QA, SA, SG, TT, VN
114
+ * [Modern Payments](http://www.modpay.com) - US
115
+ * [Moneris](http://www.moneris.com/) - CA
116
+ * [Moneris US](http://www.monerisusa.com/) - US
117
+ * [NABTransact](http://www.nab.com.au/nabtransact/) - AU
118
+ * [NELiX TransaX Gateway](http://www.nelixtransax.com) - US
119
+ * [Netaxept](http://www.betalingsterminal.no/Netthandel-forside) - NO, DK, SE, FI
120
+ * [NETbilling](http://www.netbilling.com) - US
121
+ * [NetRegistry](http://www.netregistry.com.au) - AU
122
+ * [NMI](http://nmi.com/) - US
123
+ * [Ogone DirectLink](http://www.ogone.com) - BE, DE, FR, NL, AT, CH
124
+ * [Optimal Payments](http://www.optimalpayments.com/) - CA, US, UK
125
+ * [Orbital Paymentech](http://chasepaymentech.com/) - CA, US
126
+ * [PayBox Direct](http://www.paybox.com) - FR
127
+ * [PayJunction](http://www.payjunction.com/) - US
128
+ * [PaymentExpress](http://www.paymentexpress.com/) - AU, MY, NZ, SG, ZA, UK, US
129
+ * [PayPal Express Checkout](https://www.paypal.com/cgi-bin/webscr?cmd=xpt/merchant/ExpressCheckoutIntro-outside) - US, CA, SG, AU
130
+ * [PayPal Payflow Pro](https://www.paypal.com/cgi-bin/webscr?cmd=_payflow-pro-overview-outside) - US, CA, SG, AU
131
+ * [PayPal Website Payments Pro (UK)](https://www.paypal.com/uk/cgi-bin/webscr?cmd=_wp-pro-overview-outside) - UK
132
+ * [PayPal Website Payments Pro (CA)](https://www.paypal.com/cgi-bin/webscr?cmd=_wp-pro-overview-outside) - CA
133
+ * [PayPal Express Checkout](https://www.paypal.com/cgi-bin/webscr?cmd=xpt/merchant/ExpressCheckoutIntro-outside) - US
134
+ * [PayPal Website Payments Pro (US)](https://www.paypal.com/cgi-bin/webscr?cmd=_wp-pro-overview-outside) - US
135
+ * [PaySecure](http://www.commsecure.com.au/paysecure.shtml) - AU
136
+ * [Plug'n Pay](http://www.plugnpay.com/) - US
137
+ * [Psigate](http://www.psigate.com/) - CA
138
+ * [PSL Payment Solutions](http://www.paymentsolutionsltd.com/) - UK
139
+ * [Quantum](http://www.quantumgateway.com) - US
140
+ * [QuickBooks Merchant Services](http://payments.intuit.com/) - US
141
+ * [Quickpay](http://quickpay.dk/) - DK, SE
142
+ * [Rabobank Nederland](http://www.rabobank.nl/) - NL
143
+ * [Realex](http://www.realexpayments.com/) - IE, UK
144
+ * [SagePay](http://www.sagepay.com) - UK
145
+ * [Sage Payment Solutions](http://www.sagepayments.com) - US, CA
146
+ * [Sallie Mae](http://www.salliemae.com) - US
147
+ * [SecureNet](http://www.securenet.com) - US
148
+ * [SecurePay](http://securepay.com.au) - AU
149
+ * [SecurePay](http://www.securepay.com/) - US
150
+ * [SecurePayTech](http://www.securepaytech.com/) - NZ
151
+ * [SkipJack](http://www.skipjack.com/) - US, CA
152
+ * [Stripe](https://stripe.com/) - US
153
+ * [TransFirst](http://www.transfirst.com/) - US
154
+ * [TrustCommerce](http://www.trustcommerce.com/) - US
155
+ * [USA ePay](http://www.usaepay.com/) - US
156
+ * [Verifi](http://www.verifi.com/) - US
157
+ * [ViaKLIX](http://viaklix.com) - US
158
+ * [Vindica](http://www.vindicia.com/) - US, CA, UK, AU, MX, BR, DE, KR, CN, HK
159
+ * [Wirecard](http://www.wirecard.com) - DE
160
+ * [WorldPay](http://www.worldpay.com) - AU, HK, UK, US
161
+
162
+ ## Supported Offsite Payment Gateways
163
+
164
+ * [2 Checkout](http://www.2checkout.com)
165
+ * [Authorize.Net SIM](http://developer.authorize.net/api/sim/) - US
166
+ * [Banca Sella GestPay](https://www.sella.it/banca/ecommerce/gestpay/gestpay.jsp)
167
+ * [Chronopay](http://www.chronopay.com)
168
+ * [DirecPay](http://www.timesofmoney.com/direcpay/jsp/home.jsp)
169
+ * [Direct-eBanking / sofortueberweisung.de by Payment-Networks AG](https://www.payment-network.com/deb_com_en/merchantarea/home) - DE, AT, CH, BE, UK, NL
170
+ * [Dotpay](http://dotpay.pl)
171
+ * [Dwolla](https://www.dwolla.com/default.aspx)
172
+ * [ePay](http://www.epay.dk/epay-payment-solutions/)
173
+ * [HiTRUST](http://www.hitrust.com.hk/)
174
+ * [Moneybookers](http://www.moneybookers.com)
175
+ * [Nochex](http://www.nochex.com)
176
+ * [PayPal Website Payments Standard](https://www.paypal.com/cgi-bin/webscr?cmd#_wp-standard-overview-outside)
177
+ * [Robokassa](http://robokassa.ru/)
178
+ * [SagePay Form](http://www.sagepay.com/products_services/sage_pay_go/integration/form)
179
+ * [Valitor](http://www.valitor.is/) - IS
180
+ * [Verkkomaksut](http://www.verkkomaksut.fi) - FI
181
+ * [WorldPay](http://www.worldpay.com)
182
+
183
+ ## Contributing
184
+
185
+ The source code is hosted at [GitHub](http://github.com/Shopify/active_merchant), and can be fetched using:
186
+
187
+ git clone git://github.com/Shopify/active_merchant.git
188
+
189
+ Please see the [ActiveMerchant Guide to Contributing](http://github.com/Shopify/active_merchant/wikis/contributing) for
190
+ information on adding a new gateway to ActiveMerchant.
191
+
192
+ Please don't touch the CHANGELOG in your pull requests, we'll add the appropriate CHANGELOG entries
193
+ at release time.
194
+
195
+ [![Build Status](https://secure.travis-ci.org/Shopify/active_merchant.png)](http://travis-ci.org/Shopify/active_merchant)
@@ -486,6 +486,8 @@ module ActiveMerchant #:nodoc:
486
486
  add_merchant_authentication(xml)
487
487
  # Merchant-assigned reference ID for the request
488
488
  xml.tag!('refId', options[:ref_id]) if options[:ref_id]
489
+ # Order options
490
+ add_order(xml, options[:order]) if options[:order]
489
491
  send("build_#{action}_request", xml, options)
490
492
  end
491
493
  end
@@ -4,9 +4,9 @@ module ActiveMerchant #:nodoc:
4
4
  TEST_URL = 'https://secure2.mde.epdq.co.uk:11500'
5
5
  LIVE_URL = 'https://secure2.epdq.co.uk:11500'
6
6
 
7
- self.supported_countries = ['UK']
7
+ self.supported_countries = ['GB']
8
8
  self.default_currency = 'GBP'
9
- self.supported_cardtypes = [:visa, :master, :maestro, :switch ]
9
+ self.supported_cardtypes = [:visa, :master, :american_express, :maestro, :switch ]
10
10
  self.money_format = :cents
11
11
  self.homepage_url = 'http://www.barclaycard.co.uk/business/accepting-payments/epdq-mpi/'
12
12
  self.display_name = 'Barclays ePDQ'
@@ -1,11 +1,492 @@
1
- module ActiveMerchant #:nodoc:
2
- module Billing #:nodoc:
3
- class BluePayGateway < AuthorizeNetGateway
4
- self.test_url = "https://secure.bluepay.com/interfaces/a.net.test"
5
- self.live_url = "https://secure.bluepay.com/interfaces/a.net"
6
- self.homepage_url = 'http://www.bluepay.com/'
7
- self.display_name = 'BluePay'
8
- end
9
- end
10
- end
11
-
1
+ require 'digest/md5'
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+ class BluePayGateway < Gateway
6
+ class_attribute :live_url, :rebilling_url, :ignore_http_status
7
+
8
+ self.live_url = 'https://secure.bluepay.com/interfaces/bp20post'
9
+ self.rebilling_url = 'https://secure.bluepay.com/interfaces/bp20rebadmin'
10
+
11
+ self.ignore_http_status = true
12
+
13
+ RESPONSE_CODE, RESPONSE_REASON_CODE, RESPONSE_REASON_TEXT = 0, 2, 3
14
+ AVS_RESULT_CODE, TRANSACTION_ID, CARD_CODE_RESPONSE_CODE = 5, 6, 38
15
+
16
+ CARD_CODE_ERRORS = %w( N S )
17
+ AVS_ERRORS = %w( A E N R W Z )
18
+ AVS_REASON_CODES = %w(27 45)
19
+
20
+ class_attribute :duplicate_window
21
+
22
+ self.supported_countries = ['US']
23
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb]
24
+ self.homepage_url = 'http://www.bluepay.com/'
25
+ self.display_name = 'BluePay'
26
+ self.money_format = :dollars
27
+
28
+
29
+ # Creates a new BluepayGateway
30
+ #
31
+ # The gateway requires that a valid Account ID and Secret Key be passed
32
+ # in the +options+ hash.
33
+ #
34
+ # ==== Options
35
+ #
36
+ # * <tt>:account_id</tt> -- The BluePay gateway Account ID (REQUIRED)
37
+ # * <tt>:secret_key</tt> -- The BluePay gateway Secret Key (REQUIRED)
38
+ # * <tt>:test</tt> -- set to true for TEST mode or false for LIVE mode
39
+ def initialize(options = {})
40
+ requires!(options, :login, :password)
41
+ @options = options
42
+ super
43
+ end
44
+
45
+ # Performs an authorization, which reserves the funds on the customer's credit card. This does not actually take funds from the customer
46
+ # This is referred to an AUTH transaction in BluePay
47
+ #
48
+ # ==== Parameters
49
+ #
50
+ # * <tt>money</tt> -- The amount to be authorized as an Integer value in cents.
51
+ # * <tt>payment_object</tt> -- This can either be one of three things:
52
+ # A CreditCard object,
53
+ # A Check object,
54
+ # or a token. The token is called the Master ID. This is a unique transaction ID returned from a previous transaction. This token associates all the stored information for a previous transaction.
55
+ # * <tt>options</tt> -- A hash of optional parameters.
56
+ def authorize(money, payment_object, options = {})
57
+ post = {}
58
+ post[:MASTER_ID] = ''
59
+ if payment_object != nil && payment_object.class() != String
60
+ payment_object.class() == ActiveMerchant::Billing::Check ?
61
+ add_check(post, payment_object) :
62
+ add_creditcard(post, payment_object)
63
+ else
64
+ post[:MASTER_ID] = payment_object
65
+ end
66
+ add_invoice(post, options)
67
+ add_address(post, options)
68
+ add_customer_data(post, options)
69
+ if options[:rebill] != nil
70
+ post[:DO_REBILL] = '1'
71
+ post[:REB_AMOUNT] = amount(options[:rebill_amount])
72
+ post[:REB_FIRST_DATE] = options[:rebill_start_date]
73
+ post[:REB_EXPR] = options[:rebill_expression]
74
+ post[:REB_CYCLES] = options[:rebill_cycles]
75
+ end
76
+ post[:TRANS_TYPE] = 'AUTH'
77
+ commit('AUTH_ONLY', money, post)
78
+ end
79
+
80
+ # Perform a purchase, which is essentially an authorization and capture in a single operation.
81
+ # This is referred to a SALE transaction in BluePay
82
+ #
83
+ # ==== Parameters
84
+ #
85
+ # * <tt>money</tt> -- The amount to be purchased as an Integer value in cents.
86
+ # * <tt>payment_object</tt> -- This can either be one of three things:
87
+ # A CreditCard object,
88
+ # A Check object,
89
+ # or a token. The token is called the Master ID. This is a unique transaction ID returned from a previous transaction. This token associates all the stored information for a previous transaction.
90
+ # * <tt>options</tt> -- A hash of optional parameters.,
91
+ def purchase(money, payment_object, options = {})
92
+ post = {}
93
+ post[:MASTER_ID] = ''
94
+ if payment_object != nil && payment_object.class() != String
95
+ payment_object.class() == ActiveMerchant::Billing::Check ?
96
+ add_check(post, payment_object) :
97
+ add_creditcard(post, payment_object)
98
+ else
99
+ post[:MASTER_ID] = payment_object
100
+ end
101
+ add_invoice(post, options)
102
+ add_address(post, options)
103
+ add_customer_data(post, options)
104
+ if options[:rebill] != nil
105
+ post[:DO_REBILL] = '1'
106
+ post[:REB_AMOUNT] = amount(options[:rebill_amount])
107
+ post[:REB_FIRST_DATE] = options[:rebill_start_date]
108
+ post[:REB_EXPR] = options[:rebill_expression]
109
+ post[:REB_CYCLES] = options[:rebill_cycles]
110
+ end
111
+ post[:TRANS_TYPE] = 'SALE'
112
+ commit('AUTH_CAPTURE', money, post)
113
+ end
114
+
115
+ # Captures the funds from an authorize transaction.
116
+ # This is referred to a CAPTURE transaction in BluePay
117
+ #
118
+ # ==== Parameters
119
+ #
120
+ # * <tt>money</tt> -- The amount to be captured as an Integer value in cents.
121
+ # * <tt>identification</tt> -- The Master ID, or token, returned from the previous authorize transaction.
122
+ def capture(money, identification, options = {})
123
+ post = {}
124
+ add_address(post, options)
125
+ add_customer_data(post, options)
126
+ post[:MASTER_ID] = identification
127
+ post[:TRANS_TYPE] = 'CAPTURE'
128
+ commit('PRIOR_AUTH_CAPTURE', money, post)
129
+ end
130
+
131
+ # Void a previous transaction
132
+ # This is referred to a VOID transaction in BluePay
133
+ #
134
+ # ==== Parameters
135
+ #
136
+ # * <tt>identification</tt> - The Master ID, or token, returned from a previous authorize transaction.
137
+ def void(identification, options = {})
138
+ post = {}
139
+ post[:MASTER_ID] = identification
140
+ post[:TRANS_TYPE] = 'VOID'
141
+ commit('VOID', nil, post)
142
+ end
143
+
144
+ # Performs a credit.
145
+ #
146
+ # This transaction indicates that money should flow from the merchant to the customer.
147
+ #
148
+ # ==== Parameters
149
+ #
150
+ # * <tt>money</tt> -- The amount to be credited to the customer as an Integer value in cents.
151
+ # * <tt>payment_object</tt> -- This can either be one of three things:
152
+ # A CreditCard object,
153
+ # A Check object,
154
+ # or a token. The token is called the Master ID. This is a unique transaction ID returned from a previous transaction. This token associates all the stored information for a previous transaction.
155
+ # If the payment_object is a token, then the transaction type will reverse a previous capture or purchase transaction, returning the funds to the customer. If the amount is nil, a full credit will be processed. This is referred to a REFUND transaction in BluePay.
156
+ # If the payment_object is either a CreditCard or Check object, then the transaction type will be an unmatched credit placing funds in the specified account. This is referred to a CREDIT transaction in BluePay.
157
+ # * <tt>options</tt> -- A hash of parameters.
158
+ def refund(money, payment_object, options = {})
159
+ post = {}
160
+ post[:PAYMENT_ACCOUNT] = ''
161
+ if payment_object != nil && payment_object.class() != String
162
+ payment_object.class() == ActiveMerchant::Billing::Check ?
163
+ add_check(post, payment_object) :
164
+ add_creditcard(post, payment_object)
165
+ post[:TRANS_TYPE] = 'CREDIT'
166
+ else
167
+ post[:MASTER_ID] = payment_object
168
+ post[:TRANS_TYPE] = 'REFUND'
169
+ end
170
+
171
+ options[:first_name] ? post[:NAME1] = options[:first_name] : post[:NAME1] = ''
172
+ post[:NAME2] = options[:last_name] if options[:last_name]
173
+ post[:ZIP] = options[:zip] if options[:zip]
174
+ add_invoice(post, options)
175
+ add_address(post, options)
176
+ add_customer_data(post, options)
177
+ commit('CREDIT', money, post)
178
+ end
179
+
180
+ def credit(money, identification, options = {})
181
+ deprecated CREDIT_DEPRECATION_MESSAGE
182
+ refund(money, identification, options)
183
+ end
184
+
185
+ # Create a new recurring payment.
186
+ #
187
+ # ==== Parameters
188
+ #
189
+ # * <tt>money</tt> -- The amount to charge the customer at the time of the recurring payment setup, in cents. Set to zero if you do not want the customer to be charged at this time.
190
+ # * <tt>payment_object</tt> -- This can either be one of three things:
191
+ # A CreditCard object,
192
+ # A Check object,
193
+ # or a token. The token is called the Master ID. This is a unique transaction ID returned from a previous transaction. This token associates all the stored information for a previous transaction.
194
+ # * <tt>options</tt> -- A hash of optional parameters.,
195
+
196
+ # ==== Options
197
+ #
198
+ # * <tt>:rebill_start_date</tt> is a string that tells the gateway when to start the rebill. (REQUIRED)
199
+ # Has two valid formats:
200
+ # "YYYY-MM-DD HH:MM:SS" Hours, minutes, and seconds are optional.
201
+ # "XX UNITS" Relative date as explained below. Marked from the time of the
202
+ # transaction (i.e.: 10 DAYS, 1 MONTH, 1 YEAR)
203
+ # * <tt>:rebill_expression</tt> is the period of time in-between rebillings. (REQUIRED)
204
+ # It uses the same "XX UNITS" format as rebill_start_date, explained above.
205
+ # Optional parameters include:
206
+ # * <tt>rebill_cycles</tt>: Number of times to rebill. Don't send or set to nil for infinite rebillings (or
207
+ # until canceled).
208
+ # * <tt>rebill_amount</tt>: Amount to rebill. Defaults to amount of transaction for rebillings.
209
+ #
210
+ # For example, to charge the customer $19.95 now and then charge $39.95 in 60 days every 3 months for 5 times, the options hash would be as follows:
211
+ # :rebill_start_date => '60 DAYS',
212
+ # :rebill_expression => '3 MONTHS',
213
+ # :rebill_cycles => '5',
214
+ # :rebill_amount => '39.95'
215
+ # A money object of 1995 cents would be passed into the 'money' parameter.
216
+ def recurring(money, payment_object, options = {})
217
+ requires!(options, :rebill_start_date, :rebill_expression)
218
+ options[:rebill] = '1'
219
+ money == nil ? authorize(money, payment_object, options) :
220
+ purchase(money, payment_object, options)
221
+ end
222
+
223
+ # View a recurring payment
224
+ #
225
+ # This will pull data associated with a current recurring billing
226
+ #
227
+ # ==== Parameters
228
+ #
229
+ # * <tt>rebill_id</tt> -- A string containing the rebill_id of the recurring billing that is already active (REQUIRED)
230
+ def status_recurring(rebill_id)
231
+ post = {}
232
+ requires!(rebill_id)
233
+ post[:REBILL_ID] = rebill_id
234
+ post[:TRANS_TYPE] = 'GET'
235
+ commit('rebill', 'nil', post)
236
+ end
237
+
238
+ # Update a recurring payment's details.
239
+ #
240
+ # This transaction updates an existing recurring billing
241
+ #
242
+ # ==== Options
243
+ #
244
+ # * <tt>:rebill_id</tt> -- The 12 digit rebill ID used to update a particular rebilling cycle. (REQUIRED)
245
+ # * <tt>:rebill_amount</tt> -- A string containing the new rebilling amount.
246
+ # * <tt>:rebill_next_date</tt> -- A string containing the new rebilling next date.
247
+ # * <tt>:rebill_expression</tt> -- A string containing the new rebilling expression.
248
+ # * <tt>:rebill_cycles</tt> -- A string containing the new rebilling cycles.
249
+ # * <tt>:rebill_next_amount</tt> -- A string containing the next rebilling amount to charge the customer. This ONLY affects the next scheduled charge; all other rebillings will continue at the regular (rebill_amount) amount.
250
+ # Take a look above at the recurring_payment method for similar examples on how to use.
251
+ def update_recurring(options = {})
252
+ post = {}
253
+ requires!(options, :rebill_id)
254
+ post[:REBILL_ID] = options[:rebill_id]
255
+ post[:TRANS_TYPE] = 'SET'
256
+ post[:REB_AMOUNT] = amount(options[:rebill_amount]) if !options[:rebill_amount].nil?
257
+ post[:NEXT_DATE] = options[:rebill_next_date] if !options[:rebill_next_date].nil?
258
+ post[:REB_EXPR] = options[:rebill_expression] if !options[:rebill_expression].nil?
259
+ post[:REB_CYCLES] = options[:rebill_cycles] if !options[:rebill_cycles].nil?
260
+ post[:NEXT_AMOUNT] = options[:rebill_next_amount] if !options[:rebill_next_amount].nil?
261
+ commit('rebill', 'nil', post)
262
+ end
263
+
264
+ # Cancel a recurring payment.
265
+ #
266
+ # This transaction cancels an existing recurring billing.
267
+ #
268
+ # ==== Parameters
269
+ #
270
+ # * <tt>rebill_id</tt> -- A string containing the rebill_id of the recurring billing that you wish to cancel/stop (REQUIRED)
271
+ def cancel_recurring(rebill_id)
272
+ post = {}
273
+ requires!(rebill_id)
274
+ post[:REBILL_ID] = rebill_id
275
+ post[:TRANS_TYPE] = 'SET'
276
+ post[:STATUS] = 'stopped'
277
+ commit('rebill', 'nil', post)
278
+ end
279
+
280
+ private
281
+
282
+ def commit(action, money, fields)
283
+ fields[:AMOUNT] = amount(money) unless (fields[:TRANS_TYPE] == 'VOID' or action == 'rebill')
284
+ test? == true || @options[:test] == true ? fields[:MODE] = 'TEST' : fields[:MODE] = 'LIVE'
285
+ action == 'rebill' ? begin url = rebilling_url; fields[:TAMPER_PROOF_SEAL] = calc_rebill_tps(fields) end : begin url = live_url; fields[:TAMPER_PROOF_SEAL] = calc_tps(amount(money), fields) end
286
+ fields[:ACCOUNT_ID] = @options[:login]
287
+ data = ssl_post url, post_data(action, fields)
288
+ response = parse(data)
289
+ message = message_from(response)
290
+ test_mode = test? || fields[:MODE] == 'TEST'
291
+ if (response.has_key?('TRANS_ID'))
292
+ response_id = response['TRANS_ID'].to_s()
293
+ elsif (response.has_key?('rebill_id'))
294
+ response_id = response['rebill_id'][0]
295
+ else
296
+ response_id = response[TRANSACTION_ID]
297
+ end
298
+ response.has_key?('AVS') ? avs = response['AVS'] : avs = ''
299
+ response[AVS_RESULT_CODE] != '' ? avs = response[AVS_RESULT_CODE] : avs = ''
300
+ response.has_key?('CVV2') ? cvv2 = response['CVV2'] : cvv2 = ''
301
+ response[CARD_CODE_RESPONSE_CODE] != '' ? cvv2 = response[CARD_CODE_RESPONSE_CODE] : cvv2 = ''
302
+ Response.new(success?(response), message, response,
303
+ :test => test_mode,
304
+ :authorization => response_id,
305
+ :fraud_review => fraud_review?(response),
306
+ :avs_result => { :code => avs },
307
+ :cvv_result => cvv2
308
+ )
309
+ end
310
+
311
+ def success?(response)
312
+ if (response['STATUS'] == '1' || message_from(response) =~ /approved/ || response.has_key?('rebill_id') || response[RESPONSE_REASON_TEXT] =~ /approved/)
313
+ return true
314
+ else
315
+ return false
316
+ end
317
+ end
318
+
319
+ def fraud_review?(response)
320
+ response['STATUS'] == 'E' || response['STATUS'] == '0' || response[RESPONSE_REASON_TEXT] =~ /being reviewed/
321
+ end
322
+
323
+ def get_rebill_id(response)
324
+ return response['REBID'] if response_has.key?('REBID')
325
+ end
326
+
327
+ def parse(body)
328
+ fields = CGI::parse(body)
329
+ if fields.has_key?('MESSAGE') or fields.has_key?('rebill_id')
330
+ if fields.has_key?('MESSAGE')
331
+ fields['MESSAGE'][0] == "Missing ACCOUNT_ID" ? message = "The merchant login ID or password is invalid" : message = fields['MESSAGE']
332
+ fields['MESSAGE'][0] =~ /Approved/ ? message = "This transaction has been approved" : message = fields['MESSAGE'] if message == fields['MESSAGE']
333
+ fields['MESSAGE'][0] =~ /Expired/ ? message = "The credit card has expired" : message = fields['MESSAGE'] if message == fields['MESSAGE']
334
+ fields.delete('MESSAGE')
335
+ end
336
+ fields.has_key?('STATUS') ? begin status = fields['STATUS']; fields.delete('STATUS') end : status = ''
337
+ fields.has_key?('AVS') ? begin avs = fields['AVS']; fields.delete('AVS') end : avs = ''
338
+ fields.has_key?('CVV2') ? begin cvv2 = fields['CVV2']; fields.delete('CVV2') end : cvv2 = ''
339
+ fields.has_key?('MASTER_ID') ? begin trans_id = fields['MASTER_ID']; fields.delete('MASTER_ID') end : trans_id = ''
340
+ fields[:avs_result_code] = avs
341
+ fields[:card_code] = cvv2
342
+ fields[:response_code] = status
343
+ fields[:response_reason_code] = ''
344
+ fields[:response_reason_text] = message
345
+ fields[:transaction_id] = trans_id
346
+ return fields
347
+ end
348
+ # parse response if using other old API
349
+ hash = Hash.new
350
+ fields = fields.first[0].split(",")
351
+ fields.each_index do |x|
352
+ hash[x] = fields[x].tr('$','')
353
+ end
354
+ hash
355
+ end
356
+
357
+ def add_invoice(post, options)
358
+ post[:ORDER_ID] = options[:order_id] if options.has_key? :order_id
359
+ post[:INVOICE_ID] = options[:invoice] if options.has_key? :invoice
360
+ post[:invoice_num] = options[:order_id] if options.has_key? :order_id
361
+ post[:MEMO] = options[:description] if options.has_key? :description
362
+ post[:description] = options[:description] if options.has_key? :description
363
+ end
364
+
365
+ def add_creditcard(post, creditcard)
366
+ post[:PAYMENT_TYPE] = 'CREDIT'
367
+ post[:PAYMENT_ACCOUNT] = creditcard.number
368
+ post[:CARD_CVV2] = creditcard.verification_value if
369
+ creditcard.verification_value?
370
+ post[:CARD_EXPIRE] = expdate(creditcard)
371
+ post[:NAME1] = creditcard.first_name
372
+ post[:NAME2] = creditcard.last_name
373
+ end
374
+
375
+ def add_check(post, check)
376
+ post[:PAYMENT_TYPE] = 'ACH'
377
+ post[:PAYMENT_ACCOUNT] = check.account_type + ":" + check.routing_number + ":" + check.account_number
378
+ post[:NAME1] = check.first_name
379
+ post[:NAME2] = check.last_name
380
+ end
381
+
382
+ def add_customer_data(post, options)
383
+ post[:EMAIL] = options[:email] if options.has_key? :email
384
+ post[:CUSTOM_ID] = options[:customer] if options.has_key? :customer
385
+ end
386
+
387
+ def add_duplicate_window(post)
388
+ unless duplicate_window.nil?
389
+ post[:duplicate_window] = duplicate_window
390
+ post[:DUPLICATE_OVERRIDE] = duplicate_window
391
+ end
392
+ end
393
+
394
+ def add_address(post, options)
395
+ if address = options[:billing_address] || options[:address]
396
+ post[:NAME1] = address[:first_name]
397
+ post[:NAME2] = address[:last_name]
398
+ post[:ADDR1] = address[:address1]
399
+ post[:ADDR2] = address[:address2]
400
+ post[:COMPANY_NAME] = address[:company]
401
+ post[:PHONE] = address[:phone]
402
+ post[:CITY] = address[:city]
403
+ post[:STATE] = address[:state].blank? ? 'n/a' : address[:state]
404
+ post[:ZIP] = address[:zip]
405
+ post[:COUNTRY] = address[:country]
406
+ end
407
+ if address = options[:shipping_address]
408
+ post[:NAME1] = address[:first_name]
409
+ post[:NAME2] = address[:last_name]
410
+ post[:ADDR1] = address[:address1]
411
+ post[:ADDR1] = address[:address1]
412
+ post[:COMPANY_NAME] = address[:company]
413
+ post[:PHONE] = address[:phone]
414
+ post[:ZIP] = address[:zip]
415
+ post[:CITY] = address[:city]
416
+ post[:COUNTRY] = address[:country]
417
+ post[:STATE] = address[:state].blank? ? 'n/a' : address[:state]
418
+ end
419
+ end
420
+
421
+ def post_data(action, parameters = {})
422
+ post = {}
423
+ post[:version] = '3.0'
424
+ post[:login] = ''
425
+ post[:tran_key] = ''
426
+ post[:relay_response] = "FALSE"
427
+ post[:type] = action
428
+ post[:delim_data] = "TRUE"
429
+ post[:delim_char] = ","
430
+ post[:encap_char] = "$"
431
+ post[:card_num] = '4111111111111111'
432
+ post[:exp_date] = '1212'
433
+ post[:solution_ID] = application_id if application_id.present? && application_id != "ActiveMerchant"
434
+ request = post.merge(parameters).collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&")
435
+ request
436
+ end
437
+
438
+ def message_from(results)
439
+ if results[:response_code] == 2
440
+ return CVVResult.messages[ results[:card_code] ] if CARD_CODE_ERRORS.include?(results[:card_code])
441
+ if AVS_REASON_CODES.include?(results[:response_reason_code]) && AVS_ERRORS.include?(results[:avs_result_code])
442
+ return AVSResult.messages[ results[:avs_result_code] ]
443
+ end
444
+ return (results[:response_reason_text] ? results[:response_reason_text].chomp('.') : '')
445
+ end
446
+ if results.has_key?(:response_reason_text)
447
+ return results[:response_reason_text].to_s()
448
+ end
449
+ if !results.has_key?('STATUS')
450
+ return results[RESPONSE_REASON_TEXT] ? results[RESPONSE_REASON_TEXT].chomp('.') : ''
451
+ end
452
+ end
453
+
454
+ def expdate(creditcard)
455
+ year = sprintf("%.4i", creditcard.year)
456
+ month = sprintf("%.2i", creditcard.month)
457
+
458
+ "#{month}#{year[-2..-1]}"
459
+ end
460
+
461
+ def calc_tps(amount, post)
462
+ post[:NAME1] = '' if post[:NAME1].nil?
463
+ digest = Digest::MD5.hexdigest(@options[:password] +
464
+ @options[:login] + post[:TRANS_TYPE] +
465
+ amount.to_s() + post[:MASTER_ID].to_s() +
466
+ post[:NAME1].to_s() + post[:PAYMENT_ACCOUNT].to_s())
467
+ return digest
468
+ end
469
+
470
+
471
+ def calc_rebill_tps(post)
472
+ digest = Digest::MD5.hexdigest(@options[:password] +
473
+ @options[:login] + post[:TRANS_TYPE] + post[:REBILL_ID][0].to_s())
474
+ return digest
475
+ end
476
+
477
+ def handle_response(response)
478
+ if ignore_http_status then
479
+ return response.body
480
+ else
481
+ case response.code.to_i
482
+ when 200...300
483
+ response.body
484
+ else
485
+ raise ResponseError.new(response)
486
+ end
487
+ end
488
+ end
489
+
490
+ end
491
+ end
492
+ end