diff --git a/.gitignore b/.gitignore
index 29e06144180..ac8b43785f2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,7 +5,9 @@
pkg
.rvmrc
vendor/cache
+vendor/bundle
.bundle
+.rbenv-version
# ignore Gemfile.lock because we support multiple versions of Rails and don't want to ship locked version requirements
Gemfile.lock
diff --git a/CHANGELOG b/CHANGELOG
index fb8733f206e..af398321fe9 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,7 @@
= ActiveMerchant CHANGELOG
* PayPal gateway: Support for incomplete captures [mbulat]
+* Moneris gateway: Add support for vault [kenzie]
== Version 1.23.0 (May 23, 2012)
diff --git a/lib/active_merchant/billing/gateways/moneris.rb b/lib/active_merchant/billing/gateways/moneris.rb
index 8e46a383155..09799f2dce4 100644
--- a/lib/active_merchant/billing/gateways/moneris.rb
+++ b/lib/active_merchant/billing/gateways/moneris.rb
@@ -31,18 +31,34 @@ def initialize(options = {})
# captured at a later date.
#
# Pass in +order_id+ and optionally a +customer+ parameter.
- def authorize(money, creditcard, options = {})
- debit_commit 'preauth', money, creditcard, options
+ def authorize(money, creditcard_or_datakey, options = {})
+ requires!(options, :order_id)
+ post = {}
+ add_payment_source(post, creditcard_or_datakey)
+ post[:amount] = amount(money)
+ post[:order_id] = options[:order_id]
+ post[:cust_id] = options[:customer]
+ post[:crypt_type] = options[:crypt_type] || @options[:crypt_type]
+ action = (post[:data_key].blank?) ? 'preauth' : 'res_preauth_cc'
+ commit(action, post)
end
- # This action verifies funding on a customer's card, and readies them for
+ # This action verifies funding on a customer's card and readies them for
# deposit in a merchant's account.
#
# Pass in order_id and optionally a customer parameter
- def purchase(money, creditcard, options = {})
- debit_commit 'purchase', money, creditcard, options
+ def purchase(money, creditcard_or_datakey, options = {})
+ requires!(options, :order_id)
+ post = {}
+ add_payment_source(post, creditcard_or_datakey)
+ post[:amount] = amount(money)
+ post[:order_id] = options[:order_id]
+ post[:cust_id] = options[:customer]
+ post[:crypt_type] = options[:crypt_type] || @options[:crypt_type]
+ action = (post[:data_key].blank?) ? 'purchase' : 'res_purchase_cc'
+ commit(action, post)
end
-
+
# This method retrieves locked funds from a customer's account (from a
# PreAuth) and prepares them for deposit in a merchant's account.
#
@@ -79,30 +95,46 @@ def refund(money, authorization, options = {})
commit 'refund', crediting_params(authorization, :amount => amount(money))
end
+ def store(credit_card, options = {})
+ post = {}
+ post[:pan] = credit_card.number
+ post[:expdate] = expdate(credit_card)
+ post[:crypt_type] = options[:crypt_type] || @options[:crypt_type]
+ commit('res_add_cc', post)
+ end
+
+ def unstore(data_key)
+ post = {}
+ post[:data_key] = data_key
+ commit('res_delete', post)
+ end
+
+ def update(data_key, credit_card, options = {})
+ post = {}
+ post[:pan] = credit_card.number
+ post[:expdate] = expdate(credit_card)
+ post[:data_key] = data_key
+ post[:crypt_type] = options[:crypt_type] || @options[:crypt_type]
+ commit('res_update_cc', post)
+ end
+
def test?
@options[:test] || super
end
+
private # :nodoc: all
def expdate(creditcard)
sprintf("%.4i", creditcard.year)[-2..-1] + sprintf("%.2i", creditcard.month)
end
-
- def debit_commit(commit_type, money, creditcard, options)
- requires!(options, :order_id)
- commit(commit_type, debit_params(money, creditcard, options))
- end
-
- # Common params used amongst the +purchase+ and +authorization+ methods
- def debit_params(money, creditcard, options = {})
- {
- :order_id => options[:order_id],
- :cust_id => options[:customer],
- :amount => amount(money),
- :pan => creditcard.number,
- :expdate => expdate(creditcard),
- :crypt_type => options[:crypt_type] || @options[:crypt_type]
- }
+
+ def add_payment_source(post, source)
+ if source.is_a?(String)
+ post[:data_key] = source
+ else
+ post[:pan] = source.number
+ post[:expdate] = expdate(source)
+ end
end
# Common params used amongst the +credit+, +void+ and +capture+ methods
@@ -205,7 +237,12 @@ def actions
"transact" => [:order_id, :cust_id, :amount, :pan, :expdate, :crypt_type],
"Batchcloseall" => [],
"opentotals" => [:ecr_number],
- "batchclose" => [:ecr_number]
+ "batchclose" => [:ecr_number],
+ "res_add_cc" => [:pan, :expdate, :crypt_type],
+ "res_delete" => [:data_key],
+ "res_update_cc" => [:data_key, :pan, :expdate, :crypt_type],
+ "res_purchase_cc" => [:data_key, :order_id, :cust_id, :amount, :crypt_type],
+ "res_preauth_cc" => [:data_key, :order_id, :cust_id, :amount, :crypt_type]
}
end
end
diff --git a/test/remote/gateways/remote_moneris_test.rb b/test/remote/gateways/remote_moneris_test.rb
index 18a5a5cbcb1..61a24492fa4 100644
--- a/test/remote/gateways/remote_moneris_test.rb
+++ b/test/remote/gateways/remote_moneris_test.rb
@@ -9,8 +9,7 @@ def setup
@credit_card = credit_card('4242424242424242')
@options = {
:order_id => generate_unique_id,
- :billing_address => address,
- :description => 'Store Purchase'
+ :customer => generate_unique_id
}
end
@@ -63,7 +62,7 @@ def test_successful_purchase_and_void
def test_failed_purchase_and_void
purchase = @gateway.purchase(101, @credit_card, @options)
assert_failure purchase
-
+
void = @gateway.void(purchase.authorization)
assert_failure void
end
@@ -81,4 +80,50 @@ def test_failed_purchase_from_error
assert_failure response
assert_equal 'Declined', response.message
end
+
+ def test_successful_store
+ assert response = @gateway.store(@credit_card)
+ assert_success response
+ assert_equal "Successfully registered cc details", response.message
+ assert response.params["data_key"].present?
+ @data_key = response.params["data_key"]
+ end
+
+ def test_successful_unstore
+ test_successful_store
+ assert response = @gateway.unstore(@data_key)
+ assert_success response
+ assert_equal "Successfully deleted cc details", response.message
+ assert response.params["data_key"].present?
+ end
+
+ def test_update
+ test_successful_store
+ assert response = @gateway.update(@data_key, @credit_card)
+ assert_success response
+ assert_equal "Successfully updated cc details", response.message
+ assert response.params["data_key"].present?
+ end
+
+ def test_successful_purchase_with_vault
+ test_successful_store
+ assert response = @gateway.purchase(@amount, @data_key, @options)
+ assert_success response
+ assert_equal "Approved", response.message
+ assert_false response.authorization.blank?
+ end
+
+ def test_successful_authorization_with_vault
+ test_successful_store
+ assert response = @gateway.authorize(@amount, @data_key, @options)
+ assert_success response
+ assert_false response.authorization.blank?
+ end
+
+ def test_failed_authorization_with_vault
+ test_successful_store
+ response = @gateway.authorize(105, @data_key, @options)
+ assert_failure response
+ end
+
end
diff --git a/test/unit/gateways/moneris_test.rb b/test/unit/gateways/moneris_test.rb
index c59bd88f63d..438c27cf3ab 100644
--- a/test/unit/gateways/moneris_test.rb
+++ b/test/unit/gateways/moneris_test.rb
@@ -11,7 +11,7 @@ def setup
@amount = 100
@credit_card = credit_card('4242424242424242')
- @options = { :order_id => '1', :billing_address => address }
+ @options = { :order_id => '1', :customer => '1' }
end
def test_successful_purchase
@@ -52,7 +52,6 @@ def test_amount_style
end
def test_purchase_is_valid_xml
-
params = {
:order_id => "order1",
:amount => "1.01",
@@ -67,7 +66,6 @@ def test_purchase_is_valid_xml
end
def test_purchase_is_valid_xml
-
params = {
:order_id => "order1",
:amount => "1.01",
@@ -82,7 +80,6 @@ def test_purchase_is_valid_xml
end
def test_capture_is_valid_xml
-
params = {
:order_id => "order1",
:amount => "1.01",
@@ -109,8 +106,62 @@ def test_should_raise_error_if_transaction_param_empty_on_credit_request
assert_raise(ArgumentError) { @gateway.void(invalid_transaction_param) }
end
end
-
- private
+
+
+ def test_successful_store
+ @gateway.expects(:ssl_post).returns(successful_store_response)
+ assert response = @gateway.store(@credit_card)
+ assert_success response
+ assert_equal "Successfully registered cc details", response.message
+ assert response.params["data_key"].present?
+ @data_key = response.params["data_key"]
+ end
+
+ def test_successful_unstore
+ @gateway.expects(:ssl_post).returns(successful_unstore_response)
+ test_successful_store
+ assert response = @gateway.unstore(@data_key)
+ assert_success response
+ assert_equal "Successfully deleted cc details", response.message
+ assert response.params["data_key"].present?
+ end
+
+ def test_update
+ @gateway.expects(:ssl_post).returns(successful_update_response)
+ test_successful_store
+ assert response = @gateway.update(@data_key, @credit_card)
+ assert_success response
+ assert_equal "Successfully updated cc details", response.message
+ assert response.params["data_key"].present?
+ end
+
+ def test_successful_purchase_with_vault
+ @gateway.expects(:ssl_post).returns(successful_purchase_response)
+ test_successful_store
+ assert response = @gateway.purchase(100, @data_key, {:order_id => generate_unique_id, :customer => generate_unique_id})
+ assert_success response
+ assert_equal "Approved", response.message
+ assert response.authorization.present?
+ end
+
+ def test_successful_authorization_with_vault
+ @gateway.expects(:ssl_post).returns(successful_purchase_response)
+ test_successful_store
+ assert response = @gateway.authorize(100, @data_key, {:order_id => generate_unique_id, :customer => generate_unique_id})
+ assert_success response
+ assert_equal "Approved", response.message
+ assert response.authorization.present?
+ end
+
+ def test_failed_authorization_with_vault
+ @gateway.expects(:ssl_post).returns(failed_purchase_response)
+ test_successful_store
+ assert response = @gateway.authorize(100, @data_key, @options)
+ assert_failure response
+ end
+
+ private
+
def successful_purchase_response
<<-RESPONSE
@@ -161,6 +212,50 @@ def failed_purchase_response
RESPONSE
end
+
+ def successful_store_response
+ <<-RESPONSE
+
+
+
+ 1234567890
+ 027
+ true
+ Successfully registered cc details * =
+
+
+ RESPONSE
+ end
+
+ def successful_unstore_response
+ <<-RESPONSE
+
+
+
+ 1234567890
+ 027
+ true
+ Successfully deleted cc details * =
+
+
+ RESPONSE
+ end
+
+ def successful_update_response
+ <<-RESPONSE
+
+
+
+ 1234567890
+ 027
+ true
+ Successfully updated cc details * =
+
+
+ RESPONSE
+ end
+
+
def xml_purchase_fixture
'store1yesguy1.01424242424242424203037order1'
end