activemerchant 1.32.1 → 1.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data.tar.gz.sig +0 -0
- data/CHANGELOG +41 -0
- data/CONTRIBUTORS +8 -0
- data/README.md +6 -4
- data/lib/active_merchant/billing/check.rb +4 -3
- data/lib/active_merchant/billing/credit_card.rb +7 -3
- data/lib/active_merchant/billing/gateways/authorize_net.rb +27 -7
- data/lib/active_merchant/billing/gateways/barclays_epdq.rb +8 -1
- data/lib/active_merchant/billing/gateways/blue_pay.rb +201 -185
- data/lib/active_merchant/billing/gateways/bogus.rb +1 -1
- data/lib/active_merchant/billing/gateways/card_stream_modern.rb +155 -0
- data/lib/active_merchant/billing/gateways/firstdata_e4.rb +94 -12
- data/lib/active_merchant/billing/gateways/litle.rb +41 -11
- data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +27 -6
- data/lib/active_merchant/billing/gateways/merchant_warrior.rb +2 -2
- data/lib/active_merchant/billing/gateways/net_registry.rb +8 -3
- data/lib/active_merchant/billing/gateways/netaxept.rb +65 -117
- data/lib/active_merchant/billing/gateways/orbital.rb +181 -48
- data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +12 -10
- data/lib/active_merchant/billing/gateways/paymill.rb +5 -5
- data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +11 -6
- data/lib/active_merchant/billing/gateways/paypal_express.rb +25 -7
- data/lib/active_merchant/billing/gateways/pin.rb +5 -5
- data/lib/active_merchant/billing/gateways/sage.rb +10 -5
- data/lib/active_merchant/billing/gateways/sage/sage_bankcard.rb +16 -11
- data/lib/active_merchant/billing/gateways/sage/sage_core.rb +1 -1
- data/lib/active_merchant/billing/gateways/sage/sage_virtual_check.rb +21 -16
- data/lib/active_merchant/billing/gateways/sage_pay.rb +1 -0
- data/lib/active_merchant/billing/gateways/transnational.rb +239 -0
- data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +8 -3
- data/lib/active_merchant/billing/integrations/direc_pay.rb +1 -1
- data/lib/active_merchant/billing/integrations/direc_pay/status.rb +1 -1
- data/lib/active_merchant/billing/integrations/dwolla.rb +5 -12
- data/lib/active_merchant/billing/integrations/dwolla/common.rb +21 -0
- data/lib/active_merchant/billing/integrations/dwolla/helper.rb +15 -6
- data/lib/active_merchant/billing/integrations/dwolla/notification.rb +11 -6
- data/lib/active_merchant/billing/integrations/dwolla/return.rb +12 -4
- data/lib/active_merchant/billing/integrations/notification.rb +13 -8
- data/lib/active_merchant/billing/integrations/payflow_link/helper.rb +13 -1
- data/lib/active_merchant/billing/integrations/payu_in.rb +43 -0
- data/lib/active_merchant/billing/integrations/payu_in/helper.rb +74 -0
- data/lib/active_merchant/billing/integrations/payu_in/notification.rb +167 -0
- data/lib/active_merchant/billing/integrations/payu_in/return.rb +53 -0
- data/lib/active_merchant/billing/integrations/quickpay/notification.rb +68 -5
- data/lib/active_merchant/billing/integrations/rbkmoney.rb +17 -0
- data/lib/active_merchant/billing/integrations/rbkmoney/helper.rb +23 -0
- data/lib/active_merchant/billing/integrations/rbkmoney/notification.rb +91 -0
- data/lib/active_merchant/version.rb +1 -1
- metadata +14 -4
- metadata.gz.sig +0 -0
data.tar.gz.sig
CHANGED
|
Binary file
|
data/CHANGELOG
CHANGED
|
@@ -1,5 +1,46 @@
|
|
|
1
1
|
= ActiveMerchant CHANGELOG
|
|
2
2
|
|
|
3
|
+
== Version 1.33.0 (May 30, 2013)
|
|
4
|
+
|
|
5
|
+
* Netaxept: Completely revamped to use the "M" service type [rbjordan3, ntalbott]
|
|
6
|
+
* Litle: Void authorizations via an auth reversal [jrust]
|
|
7
|
+
* Add RBK Money integration [england]
|
|
8
|
+
* Direcpay: Update test url [ashish-d]
|
|
9
|
+
* PayPal Express gateway: Add support for creating billing agreements [fabiokr]
|
|
10
|
+
* PayPal Express gateway: Add reference authorizations [fabiokr]
|
|
11
|
+
* Add Cardstream Modern gateway [ExxKA]
|
|
12
|
+
* Pin: Fix special headers [duff]
|
|
13
|
+
* PayPal Express gateway: Remember the billing agreement id as Response#authorization [duff]
|
|
14
|
+
* PayPal Express gateway: Allow an amount of 0 [duff]
|
|
15
|
+
* PayPal Express gateway: Reduce parameter requirements [duff]
|
|
16
|
+
* Quickpay integration: Update notification parser to handle API v6 [larspind]
|
|
17
|
+
* Sage gateway: Deprecate #credit call [duff]
|
|
18
|
+
* Update notification generator to better match current notification class [lulalala]
|
|
19
|
+
* Paymill gateway: Change .com -> .de [louiskearns]
|
|
20
|
+
* Quickpay integration: Fix v6 response parsing [larspind]
|
|
21
|
+
* First Data e4: Add TransArmor store/tokenization support [gabetax]
|
|
22
|
+
* MerchantWarrior: Format expiration month/year correctly [klebervirgilio]
|
|
23
|
+
* Add iconv for ActiveSupport 2.3 under Ruby 2.0 [sanemat]
|
|
24
|
+
* Add Transnational gateway [bvandenbos]
|
|
25
|
+
* Authorize.Net: Add Check as payment method [andrunix]
|
|
26
|
+
* Merchant e-Solutions: Add ref number and recurring support [carlaares]
|
|
27
|
+
* Bogus gateway: Add authorization to purchase response [hron]
|
|
28
|
+
* Bluepay gateway: Fix Check support; general cleanup [ntalbott]
|
|
29
|
+
* Dwolla: Fix security issues and enable guest checkout [capablemonkey, schonfeld]
|
|
30
|
+
* SagePay gateway: Per-transaction 3D-secure selection [ExxKA]
|
|
31
|
+
* Barclays ePDQ: Handle incorrectly encoded response [jordanwheeler, aprofeit]
|
|
32
|
+
* Orbital: Bug fixes; add CustomerEmail, Retry Logic, Managed Billing, and Destination Address [juicedM3
|
|
33
|
+
* Distinguish invalid vs empty issue_numbers on CreditCards [drasch]
|
|
34
|
+
* Float Gemfiles to latest Rails [sanemat]
|
|
35
|
+
* USA ePay Advanced: Fix Check support [RyanScottLewis]
|
|
36
|
+
* Authorize.Net: Match up Check fields better with eCheck.Net requirements [ntalbott]
|
|
37
|
+
* Bluepay: Updated to bp20post api [cagerton, melari]
|
|
38
|
+
* Net Registry: Deprecate credit method [jduff]
|
|
39
|
+
* Sage: Don't include T_customer_number unless it is numeric [melari]
|
|
40
|
+
* Auth.net: Don't include cust_id unless it is numeric [melari]
|
|
41
|
+
* Epay: Deprecate credit method [melari]
|
|
42
|
+
* New PayU.in Integration [PayU, melari]
|
|
43
|
+
|
|
3
44
|
== Version 1.32.1 (April 4, 2013)
|
|
4
45
|
|
|
5
46
|
* CC5 and Garanti: Remove $KCODE modifications [melari]
|
data/CONTRIBUTORS
CHANGED
data/README.md
CHANGED
|
@@ -12,7 +12,7 @@ Ruby applications which deal with financial transactions. It is maintained by th
|
|
|
12
12
|
[Shopify](http://www.shopify.com) and [Spreedly](https://spreedly.com) teams, with much help
|
|
13
13
|
from an ever-growing set of contributors.
|
|
14
14
|
|
|
15
|
-
See
|
|
15
|
+
See [GettingStarted.md](GettingStarted.md) if you want to learn more about using Active Merchant in your
|
|
16
16
|
applications.
|
|
17
17
|
|
|
18
18
|
## Installation
|
|
@@ -72,7 +72,7 @@ credit card details.
|
|
|
72
72
|
end
|
|
73
73
|
end
|
|
74
74
|
|
|
75
|
-
For more in-depth documentation and tutorials, see
|
|
75
|
+
For more in-depth documentation and tutorials, see [GettingStarted.md](GettingStarted.md) and the
|
|
76
76
|
[API documentation](http://rubydoc.info/github/Shopify/active_merchant/master/file/README.md).
|
|
77
77
|
|
|
78
78
|
## Supported Direct Payment Gateways
|
|
@@ -135,7 +135,7 @@ The [ActiveMerchant Wiki](http://github.com/Shopify/active_merchant/wikis) conta
|
|
|
135
135
|
* [PayGate PayXML](http://paygate.co.za/) - US, ZA
|
|
136
136
|
* [PayJunction](http://www.payjunction.com/) - US
|
|
137
137
|
* [PaymentExpress](http://www.paymentexpress.com/) - AU, MY, NZ, SG, ZA, UK, US
|
|
138
|
-
* [
|
|
138
|
+
* [PAYMILL](https://www.paymill.com) - AD, AT, BE, CH, CY, CZ, DE, DK, EE, ES, FI, FO, FR, GB, GR, HU, IE, IL, IS, IT, LI, LT, LU, LV, MT, NL, NO, PL, PT, SE, SI, SK, TR, VA
|
|
139
139
|
* [PayPal Express Checkout](https://www.paypal.com/cgi-bin/webscr?cmd=xpt/merchant/ExpressCheckoutIntro-outside) - US, CA, SG, AU
|
|
140
140
|
* [PayPal Payflow Pro](https://www.paypal.com/cgi-bin/webscr?cmd=_payflow-pro-overview-outside) - US, CA, SG, AU
|
|
141
141
|
* [PayPal Website Payments Pro (UK)](https://www.paypal.com/uk/cgi-bin/webscr?cmd=_wp-pro-overview-outside) - UK
|
|
@@ -165,6 +165,7 @@ The [ActiveMerchant Wiki](http://github.com/Shopify/active_merchant/wikis) conta
|
|
|
165
165
|
* [Spreedly Core](https://spreedlycore.com/) - AD, AE, AT, AU, BD, BE, BG, BN, CA, CH, CY, CZ, DE, DK, EE, EG, ES, FI, FR, GB, GI, GR, HK, HU, ID, IE, IL, IM, IN, IS, IT, JO, KW, LB, LI, LK, LT, LU, LV, MC, MT, MU, MV, MX, MY, NL, NO, NZ, OM, PH, PL, PT, QA, RO, SA, SE, SG, SI, SK, SM, TR, TT, UM, US, VA, VN, ZA
|
|
166
166
|
* [Stripe](https://stripe.com/) - US
|
|
167
167
|
* [TransFirst](http://www.transfirst.com/) - US
|
|
168
|
+
* [Transnational](http://www.tnbci.com/) - US
|
|
168
169
|
* [TrustCommerce](http://www.trustcommerce.com/) - US
|
|
169
170
|
* [USA ePay](http://www.usaepay.com/) - US
|
|
170
171
|
* [Verifi](http://www.verifi.com/) - US
|
|
@@ -193,7 +194,8 @@ The [ActiveMerchant Wiki](http://github.com/Shopify/active_merchant/wikis) conta
|
|
|
193
194
|
* [Paxum](https://www.paxum.com/)
|
|
194
195
|
* [PayPal Website Payments Standard](https://www.paypal.com/cgi-bin/webscr?cmd#_wp-standard-overview-outside)
|
|
195
196
|
* [Paysbuy](https://www.paysbuy.com/) - TH
|
|
196
|
-
* [
|
|
197
|
+
* [RBK Money](https://rbkmoney.ru/) - RU
|
|
198
|
+
* [Robokassa](http://robokassa.ru/) - RU
|
|
197
199
|
* [SagePay Form](http://www.sagepay.com/products_services/sage_pay_go/integration/form)
|
|
198
200
|
* [Suomen Maksuturva](https://www.maksuturva.fi/services/vendor_services/integration_guidelines.html)
|
|
199
201
|
* [Valitor](http://www.valitor.is/) - IS
|
|
@@ -4,12 +4,13 @@ module ActiveMerchant #:nodoc:
|
|
|
4
4
|
# of necessary attributes such as checkholder's name, routing and account numbers, but it is
|
|
5
5
|
# not backed by any database.
|
|
6
6
|
#
|
|
7
|
-
# You may use Check in place of CreditCard with any gateway that supports it.
|
|
8
|
-
# +BraintreeGateway+ supports the Check object.
|
|
7
|
+
# You may use Check in place of CreditCard with any gateway that supports it.
|
|
9
8
|
class Check
|
|
10
9
|
include Validateable
|
|
11
10
|
|
|
12
|
-
attr_accessor :first_name, :last_name,
|
|
11
|
+
attr_accessor :first_name, :last_name,
|
|
12
|
+
:bank_name, :routing_number, :account_number,
|
|
13
|
+
:account_holder_type, :account_type, :number
|
|
13
14
|
|
|
14
15
|
# Used for Canadian bank accounts
|
|
15
16
|
attr_accessor :institution_number, :transit_number
|
|
@@ -257,9 +257,13 @@ module ActiveMerchant #:nodoc:
|
|
|
257
257
|
def validate_switch_or_solo_attributes #:nodoc:
|
|
258
258
|
if %w[switch solo].include?(brand)
|
|
259
259
|
unless valid_month?(@start_month) && valid_start_year?(@start_year) || valid_issue_number?(@issue_number)
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
260
|
+
if @issue_number.blank?
|
|
261
|
+
errors.add :start_month, "is invalid" unless valid_month?(@start_month)
|
|
262
|
+
errors.add :start_year, "is invalid" unless valid_start_year?(@start_year)
|
|
263
|
+
errors.add :issue_number, "cannot be empty"
|
|
264
|
+
else
|
|
265
|
+
errors.add :issue_number, "is invalid" unless valid_issue_number?(@issue_number)
|
|
266
|
+
end
|
|
263
267
|
end
|
|
264
268
|
end
|
|
265
269
|
end
|
|
@@ -83,13 +83,13 @@ module ActiveMerchant #:nodoc:
|
|
|
83
83
|
# ==== Parameters
|
|
84
84
|
#
|
|
85
85
|
# * <tt>money</tt> -- The amount to be authorized as an Integer value in cents.
|
|
86
|
-
# * <tt>
|
|
86
|
+
# * <tt>paysource</tt> -- The CreditCard or Check details for the transaction.
|
|
87
87
|
# * <tt>options</tt> -- A hash of optional parameters.
|
|
88
|
-
def authorize(money,
|
|
88
|
+
def authorize(money, paysource, options = {})
|
|
89
89
|
post = {}
|
|
90
90
|
add_currency_code(post, money, options)
|
|
91
91
|
add_invoice(post, options)
|
|
92
|
-
|
|
92
|
+
add_payment_source(post, paysource, options)
|
|
93
93
|
add_address(post, options)
|
|
94
94
|
add_customer_data(post, options)
|
|
95
95
|
add_duplicate_window(post)
|
|
@@ -102,13 +102,13 @@ module ActiveMerchant #:nodoc:
|
|
|
102
102
|
# ==== Parameters
|
|
103
103
|
#
|
|
104
104
|
# * <tt>money</tt> -- The amount to be purchased as an Integer value in cents.
|
|
105
|
-
# * <tt>
|
|
105
|
+
# * <tt>paysource</tt> -- The CreditCard or Check details for the transaction.
|
|
106
106
|
# * <tt>options</tt> -- A hash of optional parameters.
|
|
107
|
-
def purchase(money,
|
|
107
|
+
def purchase(money, paysource, options = {})
|
|
108
108
|
post = {}
|
|
109
109
|
add_currency_code(post, money, options)
|
|
110
110
|
add_invoice(post, options)
|
|
111
|
-
|
|
111
|
+
add_payment_source(post, paysource, options)
|
|
112
112
|
add_address(post, options)
|
|
113
113
|
add_customer_data(post, options)
|
|
114
114
|
add_duplicate_window(post)
|
|
@@ -349,6 +349,26 @@ module ActiveMerchant #:nodoc:
|
|
|
349
349
|
post[:last_name] = creditcard.last_name
|
|
350
350
|
end
|
|
351
351
|
|
|
352
|
+
def add_payment_source(params, source, options={})
|
|
353
|
+
if card_brand(source) == "check"
|
|
354
|
+
add_check(params, source, options)
|
|
355
|
+
else
|
|
356
|
+
add_creditcard(params, source)
|
|
357
|
+
end
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
def add_check(post, check, options)
|
|
361
|
+
post[:method] = "ECHECK"
|
|
362
|
+
post[:bank_name] = check.bank_name
|
|
363
|
+
post[:bank_aba_code] = check.routing_number
|
|
364
|
+
post[:bank_acct_num] = check.account_number
|
|
365
|
+
post[:bank_acct_type] = check.account_type
|
|
366
|
+
post[:echeck_type] = "WEB"
|
|
367
|
+
post[:bank_acct_name] = check.name
|
|
368
|
+
post[:bank_check_number] = check.number if check.number.present?
|
|
369
|
+
post[:recurring_billing] = (options[:recurring] ? "TRUE" : "FALSE")
|
|
370
|
+
end
|
|
371
|
+
|
|
352
372
|
def add_customer_data(post, options)
|
|
353
373
|
if options.has_key? :email
|
|
354
374
|
post[:email] = options[:email]
|
|
@@ -356,7 +376,7 @@ module ActiveMerchant #:nodoc:
|
|
|
356
376
|
end
|
|
357
377
|
|
|
358
378
|
if options.has_key? :customer
|
|
359
|
-
post[:cust_id] = options[:customer]
|
|
379
|
+
post[:cust_id] = options[:customer] if Float(options[:customer]) rescue nil
|
|
360
380
|
end
|
|
361
381
|
|
|
362
382
|
if options.has_key? :ip
|
|
@@ -134,7 +134,14 @@ module ActiveMerchant #:nodoc:
|
|
|
134
134
|
end
|
|
135
135
|
|
|
136
136
|
def parse
|
|
137
|
-
|
|
137
|
+
require 'iconv' unless String.method_defined?(:encode)
|
|
138
|
+
if String.method_defined?(:encode)
|
|
139
|
+
doc = REXML::Document.new(@response.encode("UTF-8", "ISO-8859-1"))
|
|
140
|
+
else
|
|
141
|
+
ic = Iconv.new('UTF-8', 'ISO-8859-1')
|
|
142
|
+
doc = REXML::Document.new(ic.iconv(@response))
|
|
143
|
+
end
|
|
144
|
+
|
|
138
145
|
auth_type = find(doc, "//Transaction/Type").to_s
|
|
139
146
|
|
|
140
147
|
message = find(doc, "//Message/Text")
|
|
@@ -3,21 +3,47 @@ require 'digest/md5'
|
|
|
3
3
|
module ActiveMerchant #:nodoc:
|
|
4
4
|
module Billing #:nodoc:
|
|
5
5
|
class BluePayGateway < Gateway
|
|
6
|
-
class_attribute :
|
|
6
|
+
class_attribute :rebilling_url, :ignore_http_status
|
|
7
7
|
|
|
8
8
|
self.live_url = 'https://secure.bluepay.com/interfaces/bp20post'
|
|
9
9
|
self.rebilling_url = 'https://secure.bluepay.com/interfaces/bp20rebadmin'
|
|
10
10
|
|
|
11
11
|
self.ignore_http_status = true
|
|
12
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
13
|
CARD_CODE_ERRORS = %w( N S )
|
|
17
14
|
AVS_ERRORS = %w( A E N R W Z )
|
|
18
15
|
AVS_REASON_CODES = %w(27 45)
|
|
19
16
|
|
|
20
|
-
|
|
17
|
+
FRAUD_REVIEW_STATUSES = %w( E 0 )
|
|
18
|
+
|
|
19
|
+
FIELD_MAP = {
|
|
20
|
+
'TRANS_ID' => :transaction_id,
|
|
21
|
+
'STATUS' => :response_code,
|
|
22
|
+
'AVS' => :avs_result_code,
|
|
23
|
+
'CVV2'=> :card_code,
|
|
24
|
+
'AUTH_CODE' => :authorization,
|
|
25
|
+
'MESSAGE' => :message,
|
|
26
|
+
'REBID' => :rebid,
|
|
27
|
+
'TRANS_TYPE' => :trans_type,
|
|
28
|
+
'PAYMENT_ACCOUNT_MASK' => :acct_mask,
|
|
29
|
+
'CARD_TYPE' => :card_type,
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
REBILL_FIELD_MAP = {
|
|
33
|
+
'REBILL_ID' => :rebill_id,
|
|
34
|
+
'ACCOUNT_ID'=> :account_id,
|
|
35
|
+
'USER_ID' => :user_id,
|
|
36
|
+
'TEMPLATE_ID' => :template_id,
|
|
37
|
+
'STATUS' => :status,
|
|
38
|
+
'CREATION_DATE' => :creation_date,
|
|
39
|
+
'NEXT_DATE' => :next_date,
|
|
40
|
+
'LAST_DATE' => :last_date,
|
|
41
|
+
'SCHED_EXPR' => :schedule,
|
|
42
|
+
'CYCLES_REMAIN' => :cycles_remain,
|
|
43
|
+
'REB_AMOUNT' => :rebill_amount,
|
|
44
|
+
'NEXT_AMOUNT' => :next_amount,
|
|
45
|
+
'USUAL_DATE' => :undoc_usual_date, # Not found in the bp20rebadmin API doc.
|
|
46
|
+
}
|
|
21
47
|
|
|
22
48
|
self.supported_countries = ['US']
|
|
23
49
|
self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb]
|
|
@@ -25,7 +51,6 @@ module ActiveMerchant #:nodoc:
|
|
|
25
51
|
self.display_name = 'BluePay'
|
|
26
52
|
self.money_format = :dollars
|
|
27
53
|
|
|
28
|
-
|
|
29
54
|
# Creates a new BluepayGateway
|
|
30
55
|
#
|
|
31
56
|
# The gateway requires that a valid Account ID and Secret Key be passed
|
|
@@ -54,24 +79,12 @@ module ActiveMerchant #:nodoc:
|
|
|
54
79
|
# * <tt>options</tt> -- A hash of optional parameters.
|
|
55
80
|
def authorize(money, payment_object, options = {})
|
|
56
81
|
post = {}
|
|
57
|
-
post
|
|
58
|
-
if payment_object != nil && payment_object.class() != String
|
|
59
|
-
payment_object.class() == ActiveMerchant::Billing::Check ?
|
|
60
|
-
add_check(post, payment_object) :
|
|
61
|
-
add_creditcard(post, payment_object)
|
|
62
|
-
else
|
|
63
|
-
post[:MASTER_ID] = payment_object
|
|
64
|
-
end
|
|
82
|
+
add_payment_method(post, payment_object)
|
|
65
83
|
add_invoice(post, options)
|
|
66
84
|
add_address(post, options)
|
|
67
85
|
add_customer_data(post, options)
|
|
68
|
-
if options[:rebill]
|
|
69
|
-
|
|
70
|
-
post[:REB_AMOUNT] = amount(options[:rebill_amount])
|
|
71
|
-
post[:REB_FIRST_DATE] = options[:rebill_start_date]
|
|
72
|
-
post[:REB_EXPR] = options[:rebill_expression]
|
|
73
|
-
post[:REB_CYCLES] = options[:rebill_cycles]
|
|
74
|
-
end
|
|
86
|
+
add_rebill(post, options) if options[:rebill]
|
|
87
|
+
add_duplicate_override(post, options)
|
|
75
88
|
post[:TRANS_TYPE] = 'AUTH'
|
|
76
89
|
commit('AUTH_ONLY', money, post)
|
|
77
90
|
end
|
|
@@ -89,24 +102,12 @@ module ActiveMerchant #:nodoc:
|
|
|
89
102
|
# * <tt>options</tt> -- A hash of optional parameters.,
|
|
90
103
|
def purchase(money, payment_object, options = {})
|
|
91
104
|
post = {}
|
|
92
|
-
post
|
|
93
|
-
if payment_object != nil && payment_object.class() != String
|
|
94
|
-
payment_object.class() == ActiveMerchant::Billing::Check ?
|
|
95
|
-
add_check(post, payment_object) :
|
|
96
|
-
add_creditcard(post, payment_object)
|
|
97
|
-
else
|
|
98
|
-
post[:MASTER_ID] = payment_object
|
|
99
|
-
end
|
|
105
|
+
add_payment_method(post, payment_object)
|
|
100
106
|
add_invoice(post, options)
|
|
101
107
|
add_address(post, options)
|
|
102
108
|
add_customer_data(post, options)
|
|
103
|
-
if options[:rebill]
|
|
104
|
-
|
|
105
|
-
post[:REB_AMOUNT] = amount(options[:rebill_amount])
|
|
106
|
-
post[:REB_FIRST_DATE] = options[:rebill_start_date]
|
|
107
|
-
post[:REB_EXPR] = options[:rebill_expression]
|
|
108
|
-
post[:REB_CYCLES] = options[:rebill_cycles]
|
|
109
|
-
end
|
|
109
|
+
add_rebill(post, options) if options[:rebill]
|
|
110
|
+
add_duplicate_override(post, options)
|
|
110
111
|
post[:TRANS_TYPE] = 'SALE'
|
|
111
112
|
commit('AUTH_CAPTURE', money, post)
|
|
112
113
|
end
|
|
@@ -154,20 +155,17 @@ module ActiveMerchant #:nodoc:
|
|
|
154
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.
|
|
155
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.
|
|
156
157
|
# * <tt>options</tt> -- A hash of parameters.
|
|
157
|
-
def refund(money,
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
payment_object.class() == ActiveMerchant::Billing::Check ?
|
|
162
|
-
add_check(post, payment_object) :
|
|
163
|
-
add_creditcard(post, payment_object)
|
|
164
|
-
post[:TRANS_TYPE] = 'CREDIT'
|
|
165
|
-
else
|
|
166
|
-
post[:MASTER_ID] = payment_object
|
|
167
|
-
post[:TRANS_TYPE] = 'REFUND'
|
|
158
|
+
def refund(money, identification, options = {})
|
|
159
|
+
if(identification && !identification.kind_of?(String))
|
|
160
|
+
deprecated "refund should only be used to refund a referenced transaction"
|
|
161
|
+
return credit(money, identification, options)
|
|
168
162
|
end
|
|
169
163
|
|
|
170
|
-
|
|
164
|
+
post = {}
|
|
165
|
+
post[:PAYMENT_ACCOUNT] = ''
|
|
166
|
+
post[:MASTER_ID] = identification
|
|
167
|
+
post[:TRANS_TYPE] = 'REFUND'
|
|
168
|
+
post[:NAME1] = (options[:first_name] ? options[:first_name] : "")
|
|
171
169
|
post[:NAME2] = options[:last_name] if options[:last_name]
|
|
172
170
|
post[:ZIP] = options[:zip] if options[:zip]
|
|
173
171
|
add_invoice(post, options)
|
|
@@ -176,9 +174,24 @@ module ActiveMerchant #:nodoc:
|
|
|
176
174
|
commit('CREDIT', money, post)
|
|
177
175
|
end
|
|
178
176
|
|
|
179
|
-
def credit(money,
|
|
180
|
-
|
|
181
|
-
|
|
177
|
+
def credit(money, payment_object, options = {})
|
|
178
|
+
if(payment_object && payment_object.kind_of?(String))
|
|
179
|
+
deprecated "credit should only be used to credit a payment method"
|
|
180
|
+
return refund(money, payment_object, options)
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
post = {}
|
|
184
|
+
post[:PAYMENT_ACCOUNT] = ''
|
|
185
|
+
add_payment_method(post, payment_object)
|
|
186
|
+
post[:TRANS_TYPE] = 'CREDIT'
|
|
187
|
+
|
|
188
|
+
post[:NAME1] = (options[:first_name] ? options[:first_name] : "")
|
|
189
|
+
post[:NAME2] = options[:last_name] if options[:last_name]
|
|
190
|
+
post[:ZIP] = options[:zip] if options[:zip]
|
|
191
|
+
add_invoice(post, options)
|
|
192
|
+
add_address(post, options)
|
|
193
|
+
add_customer_data(post, options)
|
|
194
|
+
commit('CREDIT', money, post)
|
|
182
195
|
end
|
|
183
196
|
|
|
184
197
|
# Create a new recurring payment.
|
|
@@ -214,9 +227,12 @@ module ActiveMerchant #:nodoc:
|
|
|
214
227
|
# A money object of 1995 cents would be passed into the 'money' parameter.
|
|
215
228
|
def recurring(money, payment_object, options = {})
|
|
216
229
|
requires!(options, :rebill_start_date, :rebill_expression)
|
|
217
|
-
options[:rebill] =
|
|
218
|
-
|
|
219
|
-
|
|
230
|
+
options[:rebill] = true
|
|
231
|
+
if money
|
|
232
|
+
purchase(money, payment_object, options)
|
|
233
|
+
else
|
|
234
|
+
authorize(money, payment_object, options)
|
|
235
|
+
end
|
|
220
236
|
end
|
|
221
237
|
|
|
222
238
|
# View a recurring payment
|
|
@@ -252,11 +268,11 @@ module ActiveMerchant #:nodoc:
|
|
|
252
268
|
requires!(options, :rebill_id)
|
|
253
269
|
post[:REBILL_ID] = options[:rebill_id]
|
|
254
270
|
post[:TRANS_TYPE] = 'SET'
|
|
255
|
-
post[:REB_AMOUNT] = amount(options[:rebill_amount]) if
|
|
256
|
-
post[:NEXT_DATE] = options[:rebill_next_date]
|
|
257
|
-
post[:REB_EXPR] = options[:rebill_expression]
|
|
258
|
-
post[:REB_CYCLES] = options[:rebill_cycles]
|
|
259
|
-
post[:NEXT_AMOUNT] = options[:rebill_next_amount]
|
|
271
|
+
post[:REB_AMOUNT] = amount(options[:rebill_amount]) if options[:rebill_amount]
|
|
272
|
+
post[:NEXT_DATE] = options[:rebill_next_date]
|
|
273
|
+
post[:REB_EXPR] = options[:rebill_expression]
|
|
274
|
+
post[:REB_CYCLES] = options[:rebill_cycles]
|
|
275
|
+
post[:NEXT_AMOUNT] = options[:rebill_next_amount]
|
|
260
276
|
commit('rebill', 'nil', post)
|
|
261
277
|
end
|
|
262
278
|
|
|
@@ -279,117 +295,133 @@ module ActiveMerchant #:nodoc:
|
|
|
279
295
|
private
|
|
280
296
|
|
|
281
297
|
def commit(action, money, fields)
|
|
282
|
-
fields[:AMOUNT] = amount(money) unless
|
|
283
|
-
|
|
284
|
-
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
|
|
298
|
+
fields[:AMOUNT] = amount(money) unless(fields[:TRANS_TYPE] == 'VOID' || action == 'rebill')
|
|
299
|
+
fields[:MODE] = (test? ? 'TEST' : 'LIVE')
|
|
285
300
|
fields[:ACCOUNT_ID] = @options[:login]
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
if (response.has_key?('TRANS_ID'))
|
|
291
|
-
response_id = response['TRANS_ID'].to_s()
|
|
292
|
-
elsif (response.has_key?('rebill_id'))
|
|
293
|
-
response_id = response['rebill_id'][0]
|
|
301
|
+
|
|
302
|
+
if action == 'rebill'
|
|
303
|
+
url = rebilling_url
|
|
304
|
+
fields[:TAMPER_PROOF_SEAL] = calc_rebill_tps(fields)
|
|
294
305
|
else
|
|
295
|
-
|
|
306
|
+
url = live_url
|
|
307
|
+
fields[:TAMPER_PROOF_SEAL] = calc_tps(amount(money), fields)
|
|
296
308
|
end
|
|
297
|
-
|
|
298
|
-
cvv2 = (!response[CARD_CODE_RESPONSE_CODE].empty? ? response[CARD_CODE_RESPONSE_CODE] : '')
|
|
299
|
-
Response.new(success?(response), message, response,
|
|
300
|
-
:test => test_mode,
|
|
301
|
-
:authorization => response_id,
|
|
302
|
-
:fraud_review => fraud_review?(response),
|
|
303
|
-
:avs_result => { :code => avs },
|
|
304
|
-
:cvv_result => cvv2
|
|
305
|
-
)
|
|
309
|
+
parse(ssl_post(url, post_data(action, fields)))
|
|
306
310
|
end
|
|
307
311
|
|
|
308
|
-
def
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
312
|
+
def parse_recurring(response_fields, opts={}) # expected status?
|
|
313
|
+
parsed = {}
|
|
314
|
+
response_fields.each do |k,v|
|
|
315
|
+
mapped_key = REBILL_FIELD_MAP.include?(k) ? REBILL_FIELD_MAP[k] : k
|
|
316
|
+
parsed[mapped_key] = v
|
|
313
317
|
end
|
|
314
|
-
end
|
|
315
318
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
end
|
|
319
|
+
success = parsed[:status] != 'error'
|
|
320
|
+
message = parsed[:status]
|
|
319
321
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
+
Response.new(success, message, parsed,
|
|
323
|
+
:test => test?,
|
|
324
|
+
:authorization => parsed[:rebill_id])
|
|
322
325
|
end
|
|
323
326
|
|
|
324
327
|
def parse(body)
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
fields.has_key?('MASTER_ID') ? begin trans_id = fields['MASTER_ID']; fields.delete('MASTER_ID') end : trans_id = ''
|
|
337
|
-
fields[:avs_result_code] = avs
|
|
338
|
-
fields[:card_code] = cvv2
|
|
339
|
-
fields[:response_code] = status
|
|
340
|
-
fields[:response_reason_code] = ''
|
|
341
|
-
fields[:response_reason_text] = message
|
|
342
|
-
fields[:transaction_id] = trans_id
|
|
343
|
-
return fields
|
|
328
|
+
# The bp20api has max one value per form field.
|
|
329
|
+
response_fields = Hash[CGI::parse(body).map{|k,v| [k.upcase,v.first]}]
|
|
330
|
+
|
|
331
|
+
if response_fields.include? "REBILL_ID"
|
|
332
|
+
return parse_recurring(response_fields)
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
parsed = {}
|
|
336
|
+
response_fields.each do |k,v|
|
|
337
|
+
mapped_key = FIELD_MAP.include?(k) ? FIELD_MAP[k] : k
|
|
338
|
+
parsed[mapped_key] = v
|
|
344
339
|
end
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
340
|
+
|
|
341
|
+
# normalize message
|
|
342
|
+
message = message_from(parsed)
|
|
343
|
+
success = parsed[:response_code] == '1'
|
|
344
|
+
Response.new(success, message, parsed,
|
|
345
|
+
:test => test?,
|
|
346
|
+
:authorization => (parsed[:rebid] && parsed[:rebid] != '' ? parsed[:rebid] : parsed[:transaction_id]),
|
|
347
|
+
:fraud_review => FRAUD_REVIEW_STATUSES.include?(parsed[:response_code]),
|
|
348
|
+
:avs_result => { :code => parsed[:avs_result_code] },
|
|
349
|
+
:cvv_result => parsed[:card_code]
|
|
350
|
+
)
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
def message_from(parsed)
|
|
354
|
+
message = parsed[:message]
|
|
355
|
+
if(parsed[:response_code].to_i == 2)
|
|
356
|
+
if CARD_CODE_ERRORS.include?(parsed[:card_code])
|
|
357
|
+
message = CVVResult.messages[parsed[:card_code]]
|
|
358
|
+
elsif AVS_ERRORS.include?(parsed[:avs_result_code])
|
|
359
|
+
message = AVSResult.messages[ parsed[:avs_result_code] ]
|
|
360
|
+
else
|
|
361
|
+
message = message.chomp('.')
|
|
362
|
+
end
|
|
363
|
+
elsif message == "Missing ACCOUNT_ID"
|
|
364
|
+
message = "The merchant login ID or password is invalid"
|
|
365
|
+
elsif message =~ /Approved/
|
|
366
|
+
message = "This transaction has been approved"
|
|
367
|
+
elsif message =~ /Expired/
|
|
368
|
+
message = "The credit card has expired"
|
|
350
369
|
end
|
|
351
|
-
|
|
370
|
+
message
|
|
352
371
|
end
|
|
353
372
|
|
|
354
373
|
def add_invoice(post, options)
|
|
355
|
-
post[:ORDER_ID] = options[:order_id]
|
|
356
|
-
post[:INVOICE_ID] = options[:invoice]
|
|
357
|
-
post[:invoice_num] = options[:order_id]
|
|
358
|
-
post[:MEMO] = options[:description]
|
|
359
|
-
post[:description] = options[:description]
|
|
374
|
+
post[:ORDER_ID] = options[:order_id]
|
|
375
|
+
post[:INVOICE_ID] = options[:invoice]
|
|
376
|
+
post[:invoice_num] = options[:order_id]
|
|
377
|
+
post[:MEMO] = options[:description]
|
|
378
|
+
post[:description] = options[:description]
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
def add_payment_method(post, payment_object)
|
|
382
|
+
post[:MASTER_ID] = ''
|
|
383
|
+
case payment_object
|
|
384
|
+
when String
|
|
385
|
+
post[:MASTER_ID] = payment_object
|
|
386
|
+
when Check
|
|
387
|
+
add_check(post, payment_object)
|
|
388
|
+
else
|
|
389
|
+
add_creditcard(post, payment_object)
|
|
390
|
+
end
|
|
360
391
|
end
|
|
361
392
|
|
|
362
393
|
def add_creditcard(post, creditcard)
|
|
363
394
|
post[:PAYMENT_TYPE] = 'CREDIT'
|
|
364
395
|
post[:PAYMENT_ACCOUNT] = creditcard.number
|
|
365
|
-
post[:CARD_CVV2] = creditcard.verification_value
|
|
366
|
-
creditcard.verification_value?
|
|
396
|
+
post[:CARD_CVV2] = creditcard.verification_value
|
|
367
397
|
post[:CARD_EXPIRE] = expdate(creditcard)
|
|
368
398
|
post[:NAME1] = creditcard.first_name
|
|
369
399
|
post[:NAME2] = creditcard.last_name
|
|
370
400
|
end
|
|
371
401
|
|
|
402
|
+
CHECK_ACCOUNT_TYPES = {
|
|
403
|
+
"checking" => "C",
|
|
404
|
+
"savings" => "S"
|
|
405
|
+
}
|
|
406
|
+
|
|
372
407
|
def add_check(post, check)
|
|
373
408
|
post[:PAYMENT_TYPE] = 'ACH'
|
|
374
|
-
post[:PAYMENT_ACCOUNT] = check.account_type
|
|
409
|
+
post[:PAYMENT_ACCOUNT] = [CHECK_ACCOUNT_TYPES[check.account_type], check.routing_number, check.account_number].join(":")
|
|
375
410
|
post[:NAME1] = check.first_name
|
|
376
411
|
post[:NAME2] = check.last_name
|
|
377
412
|
end
|
|
378
413
|
|
|
379
414
|
def add_customer_data(post, options)
|
|
380
|
-
post[:EMAIL] = options[:email]
|
|
381
|
-
post[:CUSTOM_ID] = options[:customer]
|
|
415
|
+
post[:EMAIL] = options[:email]
|
|
416
|
+
post[:CUSTOM_ID] = options[:customer]
|
|
382
417
|
end
|
|
383
418
|
|
|
384
|
-
def
|
|
385
|
-
|
|
386
|
-
post[:duplicate_window] = duplicate_window
|
|
387
|
-
post[:DUPLICATE_OVERRIDE] = duplicate_window
|
|
388
|
-
end
|
|
419
|
+
def add_duplicate_override(post, options)
|
|
420
|
+
post[:DUPLICATE_OVERRIDE] = options[:duplicate_override]
|
|
389
421
|
end
|
|
390
422
|
|
|
391
423
|
def add_address(post, options)
|
|
392
|
-
if address = options[:billing_address] || options[:address]
|
|
424
|
+
if address = (options[:shipping_address] || options[:billing_address] || options[:address])
|
|
393
425
|
post[:NAME1] = address[:first_name]
|
|
394
426
|
post[:NAME2] = address[:last_name]
|
|
395
427
|
post[:ADDR1] = address[:address1]
|
|
@@ -397,27 +429,23 @@ module ActiveMerchant #:nodoc:
|
|
|
397
429
|
post[:COMPANY_NAME] = address[:company]
|
|
398
430
|
post[:PHONE] = address[:phone]
|
|
399
431
|
post[:CITY] = address[:city]
|
|
400
|
-
post[:STATE] = address[:state].blank?
|
|
432
|
+
post[:STATE] = (address[:state].blank? ? 'n/a' : address[:state])
|
|
401
433
|
post[:ZIP] = address[:zip]
|
|
402
434
|
post[:COUNTRY] = address[:country]
|
|
403
435
|
end
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
post[:CITY] = address[:city]
|
|
413
|
-
post[:COUNTRY] = address[:country]
|
|
414
|
-
post[:STATE] = address[:state].blank? ? 'n/a' : address[:state]
|
|
415
|
-
end
|
|
436
|
+
end
|
|
437
|
+
|
|
438
|
+
def add_rebill(post, options)
|
|
439
|
+
post[:DO_REBILL] = '1'
|
|
440
|
+
post[:REB_AMOUNT] = amount(options[:rebill_amount])
|
|
441
|
+
post[:REB_FIRST_DATE] = options[:rebill_start_date]
|
|
442
|
+
post[:REB_EXPR] = options[:rebill_expression]
|
|
443
|
+
post[:REB_CYCLES] = options[:rebill_cycles]
|
|
416
444
|
end
|
|
417
445
|
|
|
418
446
|
def post_data(action, parameters = {})
|
|
419
447
|
post = {}
|
|
420
|
-
post[:version] = '
|
|
448
|
+
post[:version] = '1'
|
|
421
449
|
post[:login] = ''
|
|
422
450
|
post[:tran_key] = ''
|
|
423
451
|
post[:relay_response] = "FALSE"
|
|
@@ -427,60 +455,48 @@ module ActiveMerchant #:nodoc:
|
|
|
427
455
|
post[:encap_char] = "$"
|
|
428
456
|
post[:card_num] = '4111111111111111'
|
|
429
457
|
post[:exp_date] = '1212'
|
|
430
|
-
post[:solution_ID] = application_id if
|
|
431
|
-
|
|
432
|
-
request
|
|
433
|
-
end
|
|
434
|
-
|
|
435
|
-
def message_from(results)
|
|
436
|
-
if results[:response_code] == 2
|
|
437
|
-
return CVVResult.messages[ results[:card_code] ] if CARD_CODE_ERRORS.include?(results[:card_code])
|
|
438
|
-
if AVS_REASON_CODES.include?(results[:response_reason_code]) && AVS_ERRORS.include?(results[:avs_result_code])
|
|
439
|
-
return AVSResult.messages[ results[:avs_result_code] ]
|
|
440
|
-
end
|
|
441
|
-
return (results[:response_reason_text] ? results[:response_reason_text].chomp('.') : '')
|
|
442
|
-
end
|
|
443
|
-
if results.has_key?(:response_reason_text)
|
|
444
|
-
return results[:response_reason_text].to_s()
|
|
445
|
-
end
|
|
446
|
-
if !results.has_key?('STATUS')
|
|
447
|
-
return results[RESPONSE_REASON_TEXT] ? results[RESPONSE_REASON_TEXT].chomp('.') : ''
|
|
448
|
-
end
|
|
458
|
+
post[:solution_ID] = application_id if(application_id && application_id != "ActiveMerchant")
|
|
459
|
+
post.merge(parameters).collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&")
|
|
449
460
|
end
|
|
450
461
|
|
|
451
462
|
def expdate(creditcard)
|
|
452
|
-
year =
|
|
453
|
-
month =
|
|
463
|
+
year = format(creditcard.year, :two_digits)
|
|
464
|
+
month = format(creditcard.month, :two_digits)
|
|
454
465
|
|
|
455
|
-
"#{month}#{year
|
|
466
|
+
"#{month}#{year}"
|
|
456
467
|
end
|
|
457
468
|
|
|
458
469
|
def calc_tps(amount, post)
|
|
459
|
-
post[:NAME1]
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
470
|
+
post[:NAME1] ||= ''
|
|
471
|
+
Digest::MD5.hexdigest(
|
|
472
|
+
[
|
|
473
|
+
@options[:password],
|
|
474
|
+
@options[:login],
|
|
475
|
+
post[:TRANS_TYPE],
|
|
476
|
+
amount,
|
|
477
|
+
post[:MASTER_ID],
|
|
478
|
+
post[:NAME1],
|
|
479
|
+
post[:PAYMENT_ACCOUNT]
|
|
480
|
+
].join("")
|
|
481
|
+
)
|
|
465
482
|
end
|
|
466
483
|
|
|
467
484
|
def calc_rebill_tps(post)
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
485
|
+
Digest::MD5.hexdigest(
|
|
486
|
+
[
|
|
487
|
+
@options[:password],
|
|
488
|
+
@options[:login],
|
|
489
|
+
post[:TRANS_TYPE],
|
|
490
|
+
post[:REBILL_ID]
|
|
491
|
+
].join("")
|
|
492
|
+
)
|
|
471
493
|
end
|
|
472
494
|
|
|
473
495
|
def handle_response(response)
|
|
474
|
-
if ignore_http_status
|
|
496
|
+
if ignore_http_status || (200...300).include?(response.code.to_i)
|
|
475
497
|
return response.body
|
|
476
|
-
else
|
|
477
|
-
case response.code.to_i
|
|
478
|
-
when 200...300
|
|
479
|
-
response.body
|
|
480
|
-
else
|
|
481
|
-
raise ResponseError.new(response)
|
|
482
|
-
end
|
|
483
498
|
end
|
|
499
|
+
raise ResponseError.new(response)
|
|
484
500
|
end
|
|
485
501
|
end
|
|
486
502
|
end
|