activemerchant 1.3.2 → 1.4.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 +58 -0
- data/CONTRIBUTERS +25 -0
- data/MIT-LICENSE +3 -3
- data/README +16 -10
- data/Rakefile +4 -3
- data/lib/active_merchant.rb +7 -1
- data/lib/active_merchant/billing/check.rb +16 -9
- data/lib/active_merchant/billing/gateway.rb +1 -1
- data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +702 -0
- data/lib/active_merchant/billing/gateways/beanstream.rb +102 -0
- data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +233 -0
- data/lib/active_merchant/billing/gateways/beanstream_interac.rb +54 -0
- data/lib/active_merchant/billing/gateways/braintree.rb +10 -1
- data/lib/active_merchant/billing/gateways/cyber_source.rb +26 -2
- data/lib/active_merchant/billing/gateways/data_cash.rb +255 -59
- data/lib/active_merchant/billing/gateways/modern_payments.rb +36 -0
- data/lib/active_merchant/billing/gateways/modern_payments_cim.rb +214 -0
- data/lib/active_merchant/billing/gateways/net_registry.rb +1 -0
- data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +2 -2
- data/lib/active_merchant/billing/gateways/payflow_express.rb +3 -11
- data/lib/active_merchant/billing/gateways/payment_express.rb +2 -2
- data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +39 -21
- data/lib/active_merchant/billing/gateways/paypal_ca.rb +13 -0
- data/lib/active_merchant/billing/gateways/paypal_express.rb +3 -12
- data/lib/active_merchant/billing/gateways/paypal_express_common.rb +20 -0
- data/lib/active_merchant/billing/gateways/protx.rb +25 -25
- data/lib/active_merchant/billing/gateways/sage.rb +145 -0
- data/lib/active_merchant/billing/gateways/sage/sage_bankcard.rb +88 -0
- data/lib/active_merchant/billing/gateways/sage/sage_core.rb +110 -0
- data/lib/active_merchant/billing/gateways/sage/sage_virtual_check.rb +97 -0
- data/lib/active_merchant/billing/gateways/secure_pay_au.rb +3 -1
- data/lib/active_merchant/billing/gateways/skip_jack.rb +2 -0
- data/lib/active_merchant/billing/gateways/trust_commerce.rb +1 -1
- data/lib/active_merchant/billing/gateways/wirecard.rb +304 -0
- data/lib/active_merchant/billing/integrations.rb +8 -2
- data/lib/active_merchant/billing/integrations/action_view_helper.rb +18 -4
- data/lib/active_merchant/billing/integrations/hi_trust/notification.rb +4 -2
- data/lib/active_merchant/billing/integrations/notification.rb +10 -1
- data/lib/active_merchant/lib/posts_data.rb +12 -3
- data/script/destroy +0 -0
- data/script/generate +0 -0
- data/test/extra/binding_of_caller.rb +0 -0
- data/test/extra/breakpoint.rb +0 -0
- data/test/fixtures.yml +24 -0
- data/test/remote/gateways/remote_authorize_net_cim_test.rb +459 -0
- data/test/remote/gateways/remote_beanstream_interac_test.rb +53 -0
- data/test/remote/gateways/remote_beanstream_test.rb +150 -0
- data/test/remote/gateways/remote_braintree_test.rb +22 -0
- data/test/remote/gateways/remote_cyber_source_test.rb +28 -3
- data/test/remote/gateways/remote_data_cash_test.rb +250 -48
- data/test/remote/gateways/remote_modern_payments_cim_test.rb +58 -0
- data/test/remote/gateways/remote_modern_payments_test.rb +43 -0
- data/test/remote/gateways/remote_sage_bankcard_test.rb +109 -0
- data/test/remote/gateways/remote_sage_test.rb +87 -0
- data/test/remote/gateways/remote_sage_virtual_check_test.rb +62 -0
- data/test/remote/gateways/remote_wirecard_test.rb +76 -0
- data/test/remote/integrations/remote_paypal_integration_test.rb +15 -3
- data/test/test_helper.rb +31 -13
- data/test/unit/check_test.rb +14 -2
- data/test/unit/credit_card_methods_test.rb +18 -0
- data/test/unit/gateways/authorize_net_cim_test.rb +641 -0
- data/test/unit/gateways/beanstream_interac_test.rb +51 -0
- data/test/unit/gateways/beanstream_test.rb +108 -0
- data/test/unit/gateways/braintree_test.rb +2 -5
- data/test/unit/gateways/cyber_source_test.rb +18 -0
- data/test/unit/gateways/data_cash_test.rb +32 -4
- data/test/unit/gateways/gateway_test.rb +8 -1
- data/test/unit/gateways/modern_payments_cim_test.rb +171 -0
- data/test/unit/gateways/net_registry_test.rb +6 -0
- data/test/unit/gateways/payflow_express_test.rb +18 -2
- data/test/unit/gateways/paypal_express_test.rb +154 -0
- data/test/unit/gateways/paypal_test.rb +140 -0
- data/test/unit/gateways/sage_bankcard_test.rb +162 -0
- data/test/unit/gateways/sage_virtual_check_test.rb +71 -0
- data/test/unit/gateways/secure_pay_au_test.rb +58 -1
- data/test/unit/gateways/skip_jack_test.rb +8 -0
- data/test/unit/gateways/verifi_test.rb +0 -1
- data/test/unit/gateways/wirecard_test.rb +232 -0
- data/test/unit/integrations/action_view_helper_test.rb +3 -0
- data/test/unit/integrations/notifications/hi_trust_notification_test.rb +23 -2
- data/test/unit/integrations/notifications/notification_test.rb +13 -0
- data/test/unit/posts_data_test.rb +20 -6
- metadata +40 -5
- metadata.gz.sig +0 -0
@@ -0,0 +1,13 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/paypal'
|
2
|
+
|
3
|
+
module ActiveMerchant #:nodoc:
|
4
|
+
module Billing #:nodoc:
|
5
|
+
# The PayPal gateway for PayPal Website Payments Pro Canada only supports Visa and MasterCard
|
6
|
+
class PaypalCaGateway < PaypalGateway
|
7
|
+
self.supported_cardtypes = [:visa, :master]
|
8
|
+
self.supported_countries = ['CA']
|
9
|
+
self.homepage_url = 'https://www.paypal.com/cgi-bin/webscr?cmd=_wp-pro-overview-outside'
|
10
|
+
self.display_name = 'PayPal Website Payments Pro (CA)'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -1,26 +1,17 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/paypal/paypal_common_api'
|
2
2
|
require File.dirname(__FILE__) + '/paypal/paypal_express_response'
|
3
|
+
require File.dirname(__FILE__) + '/paypal_express_common'
|
3
4
|
|
4
5
|
module ActiveMerchant #:nodoc:
|
5
6
|
module Billing #:nodoc:
|
6
7
|
class PaypalExpressGateway < Gateway
|
7
8
|
include PaypalCommonAPI
|
9
|
+
include PaypalExpressCommon
|
8
10
|
|
11
|
+
self.test_redirect_url = 'https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token='
|
9
12
|
self.supported_countries = ['US']
|
10
|
-
|
11
|
-
LIVE_REDIRECT_URL = 'https://www.paypal.com/cgibin/webscr?cmd=_express-checkout&token='
|
12
|
-
TEST_REDIRECT_URL = 'https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token='
|
13
|
-
|
14
13
|
self.homepage_url = 'https://www.paypal.com/cgi-bin/webscr?cmd=xpt/merchant/ExpressCheckoutIntro-outside'
|
15
14
|
self.display_name = 'PayPal Express Checkout'
|
16
|
-
|
17
|
-
def redirect_url
|
18
|
-
test? ? TEST_REDIRECT_URL : LIVE_REDIRECT_URL
|
19
|
-
end
|
20
|
-
|
21
|
-
def redirect_url_for(token)
|
22
|
-
"#{redirect_url}#{token}"
|
23
|
-
end
|
24
15
|
|
25
16
|
def setup_authorization(money, options = {})
|
26
17
|
requires!(options, :return_url, :cancel_return_url)
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module ActiveMerchant
|
2
|
+
module Billing
|
3
|
+
module PaypalExpressCommon
|
4
|
+
def self.included(base)
|
5
|
+
base.cattr_accessor :test_redirect_url
|
6
|
+
base.cattr_accessor :live_redirect_url
|
7
|
+
base.live_redirect_url = 'https://www.paypal.com/cgibin/webscr?cmd=_express-checkout&token='
|
8
|
+
end
|
9
|
+
|
10
|
+
def redirect_url
|
11
|
+
test? ? test_redirect_url : live_redirect_url
|
12
|
+
end
|
13
|
+
|
14
|
+
def redirect_url_for(token, options = {})
|
15
|
+
options = {:review => true}.update(options)
|
16
|
+
options[:review] ? "#{redirect_url}#{token}" : "#{redirect_url}#{token}&useraction=commit"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -23,6 +23,7 @@ module ActiveMerchant #:nodoc:
|
|
23
23
|
:master => "MC",
|
24
24
|
:delta => "DELTA",
|
25
25
|
:solo => "SOLO",
|
26
|
+
:switch => "MAESTRO",
|
26
27
|
:maestro => "MAESTRO",
|
27
28
|
:american_express => "AMEX",
|
28
29
|
:electron => "UKE",
|
@@ -39,7 +40,7 @@ module ActiveMerchant #:nodoc:
|
|
39
40
|
"NOTMATCHED" => 'N'
|
40
41
|
}
|
41
42
|
|
42
|
-
self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :solo, :maestro, :diners_club]
|
43
|
+
self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :switch, :solo, :maestro, :diners_club]
|
43
44
|
self.supported_countries = ['GB']
|
44
45
|
self.default_currency = 'GBP'
|
45
46
|
|
@@ -53,7 +54,7 @@ module ActiveMerchant #:nodoc:
|
|
53
54
|
end
|
54
55
|
|
55
56
|
def test?
|
56
|
-
@options[:test] ||
|
57
|
+
@options[:test] || super
|
57
58
|
end
|
58
59
|
|
59
60
|
def purchase(money, credit_card, options = {})
|
@@ -84,11 +85,13 @@ module ActiveMerchant #:nodoc:
|
|
84
85
|
commit(:authorization, post)
|
85
86
|
end
|
86
87
|
|
87
|
-
#
|
88
|
+
# You can only capture a transaction once, even if you didn't capture the full amount the first time.
|
88
89
|
def capture(money, identification, options = {})
|
89
90
|
post = {}
|
90
91
|
|
91
92
|
add_reference(post, identification)
|
93
|
+
add_release_amount(post, money, options)
|
94
|
+
|
92
95
|
commit(:capture, post)
|
93
96
|
end
|
94
97
|
|
@@ -136,10 +139,15 @@ module ActiveMerchant #:nodoc:
|
|
136
139
|
add_pair(post, :Currency, options[:currency] || currency(money), :required => true)
|
137
140
|
end
|
138
141
|
|
142
|
+
# doesn't actually use the currency -- dodgy!
|
143
|
+
def add_release_amount(post, money, options)
|
144
|
+
add_pair(post, :ReleaseAmount, amount(money), :required => true)
|
145
|
+
end
|
146
|
+
|
139
147
|
def add_customer_data(post, options)
|
140
|
-
add_pair(post, :BillingEmail, options[:email])
|
141
|
-
add_pair(post, :ContactNumber, options[:phone])
|
142
|
-
add_pair(post, :ContactFax, options[:fax])
|
148
|
+
add_pair(post, :BillingEmail, options[:email][0,255]) unless options[:email].blank?
|
149
|
+
add_pair(post, :ContactNumber, options[:phone].gsub(/[^0-9+]/, '')[0,20]) unless options[:phone].blank?
|
150
|
+
add_pair(post, :ContactFax, options[:fax].gsub(/[^0-9+]/, '')[0,20]) unless options[:fax].blank?
|
143
151
|
add_pair(post, :ClientIPAddress, options[:ip])
|
144
152
|
end
|
145
153
|
|
@@ -171,12 +179,11 @@ module ActiveMerchant #:nodoc:
|
|
171
179
|
add_pair(post, :CardHolder, credit_card.name, :required => true)
|
172
180
|
add_pair(post, :CardNumber, credit_card.number, :required => true)
|
173
181
|
|
174
|
-
add_pair(post, :ExpiryDate,
|
182
|
+
add_pair(post, :ExpiryDate, format_date(credit_card.month, credit_card.year), :required => true)
|
175
183
|
|
176
184
|
if requires_start_date_or_issue_number?(credit_card)
|
177
|
-
add_pair(post, :StartDate,
|
178
|
-
|
179
|
-
add_pair(post, :IssueNumber, format_issue_number(credit_card))
|
185
|
+
add_pair(post, :StartDate, format_date(credit_card.start_month, credit_card.start_year))
|
186
|
+
add_pair(post, :IssueNumber, credit_card.issue_number)
|
180
187
|
end
|
181
188
|
add_pair(post, :CardType, map_card_type(credit_card))
|
182
189
|
|
@@ -201,17 +208,15 @@ module ActiveMerchant #:nodoc:
|
|
201
208
|
end
|
202
209
|
|
203
210
|
# MMYY format
|
204
|
-
def
|
205
|
-
year
|
206
|
-
|
211
|
+
def format_date(month, year)
|
212
|
+
return nil if year.blank? || month.blank?
|
213
|
+
|
214
|
+
year = sprintf("%.4i", year)
|
215
|
+
month = sprintf("%.2i", month)
|
207
216
|
|
208
217
|
"#{month}#{year[-2..-1]}"
|
209
218
|
end
|
210
219
|
|
211
|
-
def format_issue_number(credit_card)
|
212
|
-
card_brand(credit_card).to_s == 'solo' ? format(credit_card.issue_number, :two_digits) : credit_card.issue_number
|
213
|
-
end
|
214
|
-
|
215
220
|
def commit(action, parameters)
|
216
221
|
response = parse( ssl_post(url_for(action), post_data(action, parameters)) )
|
217
222
|
|
@@ -230,7 +235,7 @@ module ActiveMerchant #:nodoc:
|
|
230
235
|
[ params[:VendorTxCode],
|
231
236
|
response["VPSTxId"],
|
232
237
|
response["TxAuthNo"],
|
233
|
-
response["SecurityKey"] ].
|
238
|
+
response["SecurityKey"] ].join(";")
|
234
239
|
end
|
235
240
|
|
236
241
|
def url_for(action)
|
@@ -248,12 +253,7 @@ module ActiveMerchant #:nodoc:
|
|
248
253
|
end
|
249
254
|
|
250
255
|
def message_from(response)
|
251
|
-
|
252
|
-
return 'Success'
|
253
|
-
else
|
254
|
-
return 'Unspecified error' if response["StatusDetail"].blank?
|
255
|
-
return response["StatusDetail"]
|
256
|
-
end
|
256
|
+
response['Status'] == APPROVED ? 'Success' : (response['StatusDetail'] || 'Unspecified error') # simonr 20080207 can't actually get non-nil blanks, so this is shorter
|
257
257
|
end
|
258
258
|
|
259
259
|
def post_data(action, parameters = {})
|
@@ -271,7 +271,7 @@ module ActiveMerchant #:nodoc:
|
|
271
271
|
# Key2=value2
|
272
272
|
def parse(body)
|
273
273
|
result = {}
|
274
|
-
body.to_a.
|
274
|
+
body.to_a.each { |pair| result[$1] = $2 if pair.strip =~ /\A([^=]+)=(.+)\Z/im }
|
275
275
|
result
|
276
276
|
end
|
277
277
|
|
@@ -0,0 +1,145 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/sage/sage_bankcard'
|
2
|
+
require File.dirname(__FILE__) + '/sage/sage_virtual_check'
|
3
|
+
|
4
|
+
module ActiveMerchant #:nodoc:
|
5
|
+
module Billing #:nodoc:
|
6
|
+
class SageGateway < Gateway
|
7
|
+
self.supported_cardtypes = SageBankcardGateway.supported_cardtypes
|
8
|
+
|
9
|
+
# Creates a new SageGateway
|
10
|
+
#
|
11
|
+
# The gateway requires that a valid login and password be passed
|
12
|
+
# in the +options+ hash.
|
13
|
+
#
|
14
|
+
# ==== Options
|
15
|
+
#
|
16
|
+
# * <tt>:login</tt> - The Sage Payment Solutions Merchant ID Number.
|
17
|
+
# * <tt>:password</tt> - The Sage Payment Solutions Merchant Key Number.
|
18
|
+
def initialize(options = {})
|
19
|
+
requires!(options, :login, :password)
|
20
|
+
@options = options
|
21
|
+
super
|
22
|
+
end
|
23
|
+
|
24
|
+
# Performs an authorization transaction
|
25
|
+
#
|
26
|
+
# ==== Parameters
|
27
|
+
# * <tt>money</tt> - The amount to be authorized as an integer value in cents.
|
28
|
+
# * <tt>credit_card</tt> - The CreditCard object to be used as the funding source for the transaction.
|
29
|
+
# * <tt>options</tt> - A hash of optional parameters.
|
30
|
+
# * <tt>:order_id</tt> - A unique reference for this order. (maximum of 20 characters).
|
31
|
+
# * <tt>:email</tt> - The customer's email address
|
32
|
+
# * <tt>:customer</tt> - The Customer Number for Purchase Card Level II Transactions
|
33
|
+
# * <tt>:billing_address</tt> - The customer's billing address as a hash of address information.
|
34
|
+
# * <tt>:address1</tt> - The billing address street
|
35
|
+
# * <tt>:city</tt> - The billing address city
|
36
|
+
# * <tt>:state</tt> - The billing address state
|
37
|
+
# * <tt>:country</tt> - The 2 digit ISO billing address country code
|
38
|
+
# * <tt>:zip</tt> - The billing address zip code
|
39
|
+
# * <tt>:phone</tt> - The billing address phone number
|
40
|
+
# * <tt>:fax</tt> - The billing address fax number
|
41
|
+
# * <tt>:shipping_address</tt> - The customer's shipping address as a hash of address information.
|
42
|
+
# * <tt>:name</tt> - The name at the shipping address
|
43
|
+
# * <tt>:address1</tt> - The shipping address street
|
44
|
+
# * <tt>:city</tt> - The shipping address city
|
45
|
+
# * <tt>:state</tt> - The shipping address state code
|
46
|
+
# * <tt>:country</tt> - The 2 digit ISO shipping address country code
|
47
|
+
# * <tt>:zip</tt> - The shipping address zip code
|
48
|
+
# * <tt>:tax</tt> - The tax amount for the transaction as an Integer value in cents. Maps to Sage <tt>T_tax</tt>.
|
49
|
+
# * <tt>:shipping</tt> - The shipping amount for the transaction as an Integer value in cents. Maps to Sage <tt>T_shipping</tt>.
|
50
|
+
def authorize(money, credit_card, options = {})
|
51
|
+
bankcard.authorize(money, credit_card, options)
|
52
|
+
end
|
53
|
+
|
54
|
+
# Performs a purchase, which is essentially an authorization and capture in a single operation.
|
55
|
+
#
|
56
|
+
# ==== Parameters
|
57
|
+
#
|
58
|
+
# * <tt>money</tt> - The amount to be authorized as an integer value in cents.
|
59
|
+
# * <tt>source</tt> - The CreditCard or Check object to be used as the funding source for the transaction.
|
60
|
+
# * <tt>options</tt> - A hash of optional parameters.
|
61
|
+
# * <tt>:order_id</tt> - A unique reference for this order. (maximum of 20 characters).
|
62
|
+
# * <tt>:email</tt> - The customer's email address
|
63
|
+
# * <tt>:customer</tt> - The Customer Number for Purchase Card Level II Transactions
|
64
|
+
# * <tt>:billing_address</tt> - The customer's billing address as a hash of address information.
|
65
|
+
# * <tt>:address1</tt> - The billing address street
|
66
|
+
# * <tt>:city</tt> - The billing address city
|
67
|
+
# * <tt>:state</tt> - The billing address state
|
68
|
+
# * <tt>:country</tt> - The 2 digit ISO billing address country code
|
69
|
+
# * <tt>:zip</tt> - The billing address zip code
|
70
|
+
# * <tt>:phone</tt> - The billing address phone number
|
71
|
+
# * <tt>:fax</tt> - The billing address fax number
|
72
|
+
# * <tt>:shipping_address</tt> - The customer's shipping address as a hash of address information.
|
73
|
+
# * <tt>:name</tt> - The name at the shipping address
|
74
|
+
# * <tt>:address1</tt> - The shipping address street
|
75
|
+
# * <tt>:city</tt> - The shipping address city
|
76
|
+
# * <tt>:state</tt> - The shipping address state code
|
77
|
+
# * <tt>:country</tt> - The 2 digit ISO shipping address country code
|
78
|
+
# * <tt>:zip</tt> - The shipping address zip code
|
79
|
+
# * <tt>:tax</tt> - The tax amount for the transaction as an integer value in cents. Maps to Sage <tt>T_tax</tt>.
|
80
|
+
# * <tt>:shipping</tt> - The shipping amount for the transaction as an integer value in cents. Maps to Sage <tt>T_shipping</tt>.
|
81
|
+
#
|
82
|
+
# ==== Additional options in the +options+ hash for when using a Check as the funding source
|
83
|
+
# * <tt>:originator_id</tt> - 10 digit originator. If not provided, Sage will use the default Originator ID for the specific customer type.
|
84
|
+
# * <tt>:addenda</tt> - Transaction addenda.
|
85
|
+
# * <tt>:ssn</tt> - The customer's Social Security Number.
|
86
|
+
# * <tt>:drivers_license_state</tt> - The customer's drivers license state code.
|
87
|
+
# * <tt>:drivers_license_number</tt> - The customer's drivers license number.
|
88
|
+
# * <tt>:date_of_birth</tt> - The customer's date of birth as a Time or Date object or a string in the format <tt>mm/dd/yyyy</tt>.
|
89
|
+
def purchase(money, source, options = {})
|
90
|
+
if source.type == "check"
|
91
|
+
virtual_check.purchase(money, source, options)
|
92
|
+
else
|
93
|
+
bankcard.purchase(money, source, options)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# Captures authorized funds.
|
98
|
+
#
|
99
|
+
# ==== Parameters
|
100
|
+
#
|
101
|
+
# * <tt>money</tt> - The amount to be authorized as an integer value in cents. Sage doesn't support changing the capture amount, so the full amount of the initial transaction will be captured.
|
102
|
+
# * <tt>reference</tt> - The authorization reference string returned by the original transaction's Response#authorization.
|
103
|
+
def capture(money, reference, options = {})
|
104
|
+
bankcard.capture(money, reference, options)
|
105
|
+
end
|
106
|
+
|
107
|
+
# Voids a prior transaction. Works for both CreditCard and Check transactions.
|
108
|
+
#
|
109
|
+
# ==== Parameters
|
110
|
+
#
|
111
|
+
# * <tt>reference</tt> - The authorization reference string returned by the original transaction's Response#authorization.
|
112
|
+
def void(reference, options = {})
|
113
|
+
if reference.split(";").last == "virtual_check"
|
114
|
+
virtual_check.void(reference, options)
|
115
|
+
else
|
116
|
+
bankcard.void(reference, options)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# Performs a credit transaction. (Sage +Credit+ transaction).
|
121
|
+
#
|
122
|
+
# ==== Parameters
|
123
|
+
#
|
124
|
+
# * <tt>money</tt> - The amount to be authorized as an integer value in cents.
|
125
|
+
# * <tt>source</tt> - The CreditCard or Check object to be used as the target for the credit.
|
126
|
+
def credit(money, source, options = {})
|
127
|
+
if source.type == "check"
|
128
|
+
virtual_check.credit(money, source, options)
|
129
|
+
else
|
130
|
+
bankcard.credit(money, source, options)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
private
|
135
|
+
def bankcard
|
136
|
+
@bankcard ||= SageBankcardGateway.new(@options)
|
137
|
+
end
|
138
|
+
|
139
|
+
def virtual_check
|
140
|
+
@virtual_check ||= SageVirtualCheckGateway.new(@options)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/sage_core'
|
2
|
+
|
3
|
+
module ActiveMerchant #:nodoc:
|
4
|
+
module Billing #:nodoc:
|
5
|
+
class SageBankcardGateway < Gateway #:nodoc:
|
6
|
+
include SageCore
|
7
|
+
self.url = 'https://www.sagepayments.net/cgi-bin/eftBankcard.dll?transaction'
|
8
|
+
self.source = 'bankcard'
|
9
|
+
|
10
|
+
# Credit cards supported by Sage
|
11
|
+
# * VISA
|
12
|
+
# * MasterCard
|
13
|
+
# * AMEX
|
14
|
+
# * Diners
|
15
|
+
# * Carte Blanche
|
16
|
+
# * Discover
|
17
|
+
# * JCB
|
18
|
+
# * Sears
|
19
|
+
self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :diners_club]
|
20
|
+
|
21
|
+
def authorize(money, credit_card, options = {})
|
22
|
+
post = {}
|
23
|
+
add_credit_card(post, credit_card)
|
24
|
+
add_transaction_data(post, money, options)
|
25
|
+
commit(:authorization, post)
|
26
|
+
end
|
27
|
+
|
28
|
+
def purchase(money, credit_card, options = {})
|
29
|
+
post = {}
|
30
|
+
add_credit_card(post, credit_card)
|
31
|
+
add_transaction_data(post, money, options)
|
32
|
+
commit(:purchase, post)
|
33
|
+
end
|
34
|
+
|
35
|
+
# The +money+ amount is not used. The entire amount of the
|
36
|
+
# initial authorization will be captured.
|
37
|
+
def capture(money, reference, options = {})
|
38
|
+
post = {}
|
39
|
+
add_reference(post, reference)
|
40
|
+
commit(:capture, post)
|
41
|
+
end
|
42
|
+
|
43
|
+
def void(reference, options = {})
|
44
|
+
post = {}
|
45
|
+
add_reference(post, reference)
|
46
|
+
commit(:void, post)
|
47
|
+
end
|
48
|
+
|
49
|
+
def credit(money, credit_card, options = {})
|
50
|
+
post = {}
|
51
|
+
add_credit_card(post, credit_card)
|
52
|
+
add_transaction_data(post, money, options)
|
53
|
+
commit(:credit, post)
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
def exp_date(credit_card)
|
58
|
+
year = sprintf("%.4i", credit_card.year)
|
59
|
+
month = sprintf("%.2i", credit_card.month)
|
60
|
+
|
61
|
+
"#{month}#{year[-2..-1]}"
|
62
|
+
end
|
63
|
+
|
64
|
+
def add_credit_card(post, credit_card)
|
65
|
+
post[:C_name] = credit_card.name
|
66
|
+
post[:C_cardnumber] = credit_card.number
|
67
|
+
post[:C_exp] = exp_date(credit_card)
|
68
|
+
post[:C_cvv] = credit_card.verification_value if credit_card.verification_value?
|
69
|
+
end
|
70
|
+
|
71
|
+
def parse(data)
|
72
|
+
response = {}
|
73
|
+
response[:success] = data[1,1]
|
74
|
+
response[:code] = data[2,6]
|
75
|
+
response[:message] = data[8,32].strip
|
76
|
+
response[:front_end] = data[40, 2]
|
77
|
+
response[:cvv_result] = data[42, 1]
|
78
|
+
response[:avs_result] = data[43, 1].strip
|
79
|
+
response[:risk] = data[44, 2]
|
80
|
+
response[:reference] = data[46, 10]
|
81
|
+
|
82
|
+
response[:order_number], response[:recurring] = data[57...-1].split("\034")
|
83
|
+
response
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
@@ -0,0 +1,110 @@
|
|
1
|
+
module ActiveMerchant #:nodoc:
|
2
|
+
module Billing #:nodoc:
|
3
|
+
module SageCore #:nodoc:
|
4
|
+
def self.included(base)
|
5
|
+
base.cattr_accessor :url
|
6
|
+
base.cattr_accessor :source
|
7
|
+
base.supported_countries = ['US', 'CA']
|
8
|
+
base.homepage_url = 'http://www.sagepayments.com'
|
9
|
+
base.display_name = 'Sage Payment Solutions'
|
10
|
+
end
|
11
|
+
|
12
|
+
# Transactions types:
|
13
|
+
# <tt>01</tt> - Sale
|
14
|
+
# <tt>02</tt> - AuthOnly
|
15
|
+
# <tt>03</tt> - Force/PriorAuthSale
|
16
|
+
# <tt>04</tt> - Void
|
17
|
+
# <tt>06</tt> - Credit
|
18
|
+
# <tt>11</tt> - PriorAuthSale by Reference*
|
19
|
+
TRANSACTIONS = {
|
20
|
+
:purchase => '01',
|
21
|
+
:authorization => '02',
|
22
|
+
:capture => '11',
|
23
|
+
:void => '04',
|
24
|
+
:credit => '06'
|
25
|
+
}
|
26
|
+
|
27
|
+
def initialize(options = {})
|
28
|
+
requires!(options, :login, :password)
|
29
|
+
@options = options
|
30
|
+
super
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
def add_invoice(post, options)
|
35
|
+
post[:T_ordernum] = options[:order_id].slice(0, 20)
|
36
|
+
post[:T_tax] = amount(options[:tax]) unless options[:tax].blank?
|
37
|
+
post[:T_shipping] = amount(options[:shipping]) unless options[:shipping].blank?
|
38
|
+
end
|
39
|
+
|
40
|
+
def add_reference(post, reference)
|
41
|
+
ref, source = reference.to_s.split(";")
|
42
|
+
post[:T_reference] = ref
|
43
|
+
end
|
44
|
+
|
45
|
+
def add_amount(post, money)
|
46
|
+
post[:T_amt] = amount(money)
|
47
|
+
end
|
48
|
+
|
49
|
+
def add_customer_data(post, options)
|
50
|
+
post[:T_customer_number] = options[:customer]
|
51
|
+
end
|
52
|
+
|
53
|
+
def add_addresses(post, options)
|
54
|
+
billing_address = options[:billing_address] || options[:address] || {}
|
55
|
+
|
56
|
+
post[:C_address] = billing_address[:address1]
|
57
|
+
post[:C_city] = billing_address[:city]
|
58
|
+
post[:C_state] = billing_address[:state]
|
59
|
+
post[:C_zip] = billing_address[:zip]
|
60
|
+
post[:C_country] = billing_address[:country]
|
61
|
+
post[:C_telephone] = billing_address[:phone]
|
62
|
+
post[:C_fax] = billing_address[:fax]
|
63
|
+
post[:C_email] = options[:email]
|
64
|
+
|
65
|
+
if shipping_address = options[:shipping_address]
|
66
|
+
post[:C_ship_name] = shipping_address[:name]
|
67
|
+
post[:C_ship_address] = shipping_address[:address1]
|
68
|
+
post[:C_ship_city] = shipping_address[:city]
|
69
|
+
post[:C_ship_state] = shipping_address[:state]
|
70
|
+
post[:C_ship_zip] = shipping_address[:zip]
|
71
|
+
post[:C_ship_country] = shipping_address[:country]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def add_transaction_data(post, money, options)
|
76
|
+
add_amount(post, money)
|
77
|
+
add_invoice(post, options)
|
78
|
+
add_addresses(post, options)
|
79
|
+
add_customer_data(post, options)
|
80
|
+
end
|
81
|
+
|
82
|
+
def commit(action, params)
|
83
|
+
response = parse(ssl_post(url, post_data(action, params)))
|
84
|
+
|
85
|
+
Response.new(success?(response), response[:message], response,
|
86
|
+
:test => test?,
|
87
|
+
:authorization => authorization_from(response),
|
88
|
+
:avs_result => { :code => response[:avs_result] },
|
89
|
+
:cvv_result => response[:cvv_result]
|
90
|
+
)
|
91
|
+
end
|
92
|
+
|
93
|
+
def authorization_from(response)
|
94
|
+
"#{response[:reference]};#{source}"
|
95
|
+
end
|
96
|
+
|
97
|
+
def success?(response)
|
98
|
+
response[:success] == 'A'
|
99
|
+
end
|
100
|
+
|
101
|
+
def post_data(action, params = {})
|
102
|
+
params[:M_id] = @options[:login]
|
103
|
+
params[:M_key] = @options[:password]
|
104
|
+
params[:T_code] = TRANSACTIONS[action]
|
105
|
+
|
106
|
+
params.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&")
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|