Skip to content

Commit

Permalink
Moneris gateway: Add support for vault
Browse files Browse the repository at this point in the history
Adds #store, #unstore, and #update, and support for them to #authorize
and #capture.

Closes activemerchant#369.
  • Loading branch information
kenzie authored and ntalbott committed Jun 8, 2012
1 parent 89ad9ca commit 426d026
Show file tree
Hide file tree
Showing 5 changed files with 212 additions and 32 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions 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)

Expand Down
83 changes: 60 additions & 23 deletions lib/active_merchant/billing/gateways/moneris.rb
Expand Up @@ -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 <tt>order_id</tt> and optionally a <tt>customer</tt> 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.
#
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
51 changes: 48 additions & 3 deletions test/remote/gateways/remote_moneris_test.rb
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand All @@ -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
107 changes: 101 additions & 6 deletions test/unit/gateways/moneris_test.rb
Expand Up @@ -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
Expand Down Expand Up @@ -52,7 +52,6 @@ def test_amount_style
end

def test_purchase_is_valid_xml

params = {
:order_id => "order1",
:amount => "1.01",
Expand All @@ -67,7 +66,6 @@ def test_purchase_is_valid_xml
end

def test_purchase_is_valid_xml

params = {
:order_id => "order1",
:amount => "1.01",
Expand All @@ -82,7 +80,6 @@ def test_purchase_is_valid_xml
end

def test_capture_is_valid_xml

params = {
:order_id => "order1",
:amount => "1.01",
Expand All @@ -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
<?xml version="1.0"?>
Expand Down Expand Up @@ -161,6 +212,50 @@ def failed_purchase_response
RESPONSE
end


def successful_store_response
<<-RESPONSE
<?xml version="1.0"?>
<response>
<receipt>
<DataKey>1234567890</DataKey>
<ResponseCode>027</ResponseCode>
<Complete>true</Complete>
<Message>Successfully registered cc details * =</Message>
</receipt>
</response>
RESPONSE
end

def successful_unstore_response
<<-RESPONSE
<?xml version="1.0"?>
<response>
<receipt>
<DataKey>1234567890</DataKey>
<ResponseCode>027</ResponseCode>
<Complete>true</Complete>
<Message>Successfully deleted cc details * =</Message>
</receipt>
</response>
RESPONSE
end

def successful_update_response
<<-RESPONSE
<?xml version="1.0"?>
<response>
<receipt>
<DataKey>1234567890</DataKey>
<ResponseCode>027</ResponseCode>
<Complete>true</Complete>
<Message>Successfully updated cc details * =</Message>
</receipt>
</response>
RESPONSE
end


def xml_purchase_fixture
'<request><store_id>store1</store_id><api_token>yesguy</api_token><purchase><amount>1.01</amount><pan>4242424242424242</pan><expdate>0303</expdate><crypt_type>7</crypt_type><order_id>order1</order_id></purchase></request>'
end
Expand Down

0 comments on commit 426d026

Please sign in to comment.