atmos-braintree_transparent_redirect_slice 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README +41 -0
- data/Rakefile +65 -0
- data/TODO +15 -0
- data/app/controllers/application.rb +5 -0
- data/app/controllers/credit_cards.rb +54 -0
- data/app/controllers/main.rb +7 -0
- data/app/controllers/payments.rb +17 -0
- data/app/helpers/application_helper.rb +63 -0
- data/app/helpers/credit_cards_helper.rb +15 -0
- data/app/models/braintree/gateway_request.rb +55 -0
- data/app/models/braintree/gateway_response.rb +101 -0
- data/app/models/braintree/query.rb +46 -0
- data/app/models/braintree/transaction_info.rb +20 -0
- data/app/models/credit_card.rb +18 -0
- data/app/models/credit_card_info.rb +31 -0
- data/app/models/credit_card_invoice.rb +15 -0
- data/app/views/braintree_transparent_redirect_slice/credit_cards/_form.html.haml +27 -0
- data/app/views/braintree_transparent_redirect_slice/credit_cards/_gateway_request.html.haml +6 -0
- data/app/views/braintree_transparent_redirect_slice/credit_cards/destroy.html.haml +8 -0
- data/app/views/braintree_transparent_redirect_slice/credit_cards/edit.html.haml +8 -0
- data/app/views/braintree_transparent_redirect_slice/credit_cards/index.html.haml +26 -0
- data/app/views/braintree_transparent_redirect_slice/credit_cards/new.html.haml +9 -0
- data/app/views/braintree_transparent_redirect_slice/credit_cards/show.html.haml +33 -0
- data/app/views/braintree_transparent_redirect_slice/payments/index.html.haml +2 -0
- data/app/views/braintree_transparent_redirect_slice/payments/new.html.haml +21 -0
- data/app/views/layout/braintree_transparent_redirect_slice.html.haml +26 -0
- data/app/views/main/index.html.haml +1 -0
- data/lib/braintree_transparent_redirect_slice.rb +103 -0
- data/lib/braintree_transparent_redirect_slice/merbtasks.rb +103 -0
- data/lib/braintree_transparent_redirect_slice/slicetasks.rb +20 -0
- data/lib/braintree_transparent_redirect_slice/spectasks.rb +53 -0
- data/lib/braintree_transparent_redirect_slice/version.rb +3 -0
- data/public/javascripts/master.js +6 -0
- data/public/stylesheets/master.css +153 -0
- data/spec/fixtures/user.rb +24 -0
- data/spec/models/credit_card_info_spec.rb +30 -0
- data/spec/requests/credit_cards/adding_a_card_spec.rb +110 -0
- data/spec/requests/credit_cards/deleting_a_card_spec.rb +19 -0
- data/spec/requests/credit_cards/updating_a_card_spec.rb +56 -0
- data/spec/requests/main_spec.rb +14 -0
- data/spec/requests/payments/issuing_a_transaction_spec.rb +49 -0
- data/spec/spec_helper.rb +127 -0
- data/spec/spec_helpers/braintree/api_helper.rb +14 -0
- data/spec/spec_helpers/edit_form_helper.rb +34 -0
- data/stubs/app/controllers/application.rb +2 -0
- data/stubs/app/controllers/main.rb +2 -0
- metadata +212 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Corey Donohoe
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
BraintreeTransparentRedirectSlice
|
2
|
+
=================================
|
3
|
+
|
4
|
+
A slice for the Merb framework that lets you store shit securely in Braintree's
|
5
|
+
vault (http://dev.braintreepaymentsolutions.com/vault/transparent-redirect/).
|
6
|
+
You get tokens for user's sensitive info and you can charge against those
|
7
|
+
tokens. The information is securely stored in Braintree's vault to allow you
|
8
|
+
to charge against credit cards without having ANY sensitive information pass
|
9
|
+
through your controller actions or logs. It's quite cool.
|
10
|
+
|
11
|
+
------------------------------------------------------------------------------
|
12
|
+
|
13
|
+
Installation
|
14
|
+
------------
|
15
|
+
% grep braintree_transparent_redirect config/*.rb
|
16
|
+
dependency "braintree_transparent_redirect_slice", "=1.0.7.1"
|
17
|
+
|
18
|
+
------------------------------------------------------------------------------
|
19
|
+
# example: /:controller/:action/:id
|
20
|
+
slice(:BraintreeTransparentRedirectSlice)
|
21
|
+
|
22
|
+
# example: /billing/controller/:action/:id
|
23
|
+
add_slice(:braintree_transparent_redirect_slice, :name_prefix => nil, :path_prefix => "billing")
|
24
|
+
|
25
|
+
Normally you should also run the following rake task:
|
26
|
+
rake slices:braintree_transparent_redirect_slice:install
|
27
|
+
------------------------------------------------------------------------------
|
28
|
+
|
29
|
+
Goals
|
30
|
+
-----
|
31
|
+
* actually work, as in all specs passing
|
32
|
+
* sanitize and abstract the braintree models into a gem you can use outside of merb
|
33
|
+
* hook into merb-auth so you can associate vault items into more than just the user.
|
34
|
+
i.e. instance method on the session perhaps
|
35
|
+
* support bank account info, not just credit cards
|
36
|
+
|
37
|
+
Developing
|
38
|
+
----------
|
39
|
+
% thor merb:gem:install
|
40
|
+
% cp config/braintree.yml-example config/braintree.yml
|
41
|
+
% bin/rake
|
data/Rakefile
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake/gempackagetask'
|
3
|
+
|
4
|
+
require 'merb-core'
|
5
|
+
require 'merb-core/tasks/merb'
|
6
|
+
require 'lib/braintree_transparent_redirect_slice/version'
|
7
|
+
|
8
|
+
GEM_NAME = "braintree_transparent_redirect_slice"
|
9
|
+
AUTHOR = "Corey Donohoe"
|
10
|
+
EMAIL = "atmos@atmos.org"
|
11
|
+
HOMEPAGE = "http://github.com/atmos/braintree_transparent_redirect_slice/"
|
12
|
+
SUMMARY = "Merb Slice that allows you to process stuff with braintree, without storing credit cards and shit"
|
13
|
+
GEM_VERSION = BraintreeTransparentRedirectSlice::VERSION
|
14
|
+
|
15
|
+
spec = Gem::Specification.new do |s|
|
16
|
+
s.rubyforge_project = 'merb'
|
17
|
+
s.name = GEM_NAME
|
18
|
+
s.version = GEM_VERSION
|
19
|
+
s.platform = Gem::Platform::RUBY
|
20
|
+
s.has_rdoc = true
|
21
|
+
s.extra_rdoc_files = ["README", "LICENSE", 'TODO']
|
22
|
+
s.summary = SUMMARY
|
23
|
+
s.description = s.summary
|
24
|
+
s.author = AUTHOR
|
25
|
+
s.email = EMAIL
|
26
|
+
s.homepage = HOMEPAGE
|
27
|
+
s.add_dependency 'merb-slices', '>= 1.0.7.1'
|
28
|
+
s.add_dependency 'libxml-ruby', '=0.9.7'
|
29
|
+
s.add_dependency 'dm-core', '>=0.9.8'
|
30
|
+
s.add_dependency 'dm-validations', '>=0.9.8'
|
31
|
+
s.add_dependency 'merb-auth-core'
|
32
|
+
s.add_dependency 'merb-auth-more'
|
33
|
+
s.add_dependency 'merb-haml'
|
34
|
+
s.add_dependency 'merb-helpers'
|
35
|
+
s.add_dependency 'merb-assets'
|
36
|
+
s.add_dependency 'merb-action-args'
|
37
|
+
s.require_path = 'lib'
|
38
|
+
s.files = %w(LICENSE README Rakefile TODO) + Dir.glob("{lib,spec,app,public,stubs}/**/*")
|
39
|
+
end
|
40
|
+
|
41
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
42
|
+
pkg.gem_spec = spec
|
43
|
+
end
|
44
|
+
|
45
|
+
desc "Install the gem"
|
46
|
+
task :install do
|
47
|
+
Merb::RakeHelper.install(GEM_NAME, :version => GEM_VERSION)
|
48
|
+
end
|
49
|
+
|
50
|
+
desc "Uninstall the gem"
|
51
|
+
task :uninstall do
|
52
|
+
Merb::RakeHelper.uninstall(GEM_NAME, :version => GEM_VERSION)
|
53
|
+
end
|
54
|
+
|
55
|
+
desc "Create a gemspec file"
|
56
|
+
task :gemspec do
|
57
|
+
File.open("#{GEM_NAME}.gemspec", "w") do |file|
|
58
|
+
file.puts spec.to_ruby
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
require 'spec/rake/spectask'
|
63
|
+
require 'merb-core/test/tasks/spectasks'
|
64
|
+
desc 'Default: run spec examples'
|
65
|
+
task :default => 'spec'
|
data/TODO
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
TODO:
|
2
|
+
|
3
|
+
- Fix BraintreeTransparentRedirectSlice.description and BraintreeTransparentRedirectSlice.version
|
4
|
+
- Fix LICENSE with your name
|
5
|
+
- Fix Rakefile with your name and contact info
|
6
|
+
- Add your code to lib/braintree_transparent_redirect_slice.rb
|
7
|
+
- Add your Merb rake tasks to lib/braintree_transparent_redirect_slice/merbtasks.rb
|
8
|
+
|
9
|
+
Remove anything that you don't need:
|
10
|
+
|
11
|
+
- app/controllers/main.rb BraintreeTransparentRedirectSlice::Main controller
|
12
|
+
- app/views/layout/braintree_transparent_redirect_slice.html.erb
|
13
|
+
- spec/controllers/main_spec.rb controller specs
|
14
|
+
- public/* any public files
|
15
|
+
- stubs/* any stub files
|
@@ -0,0 +1,54 @@
|
|
1
|
+
class BraintreeTransparentRedirectSlice::CreditCards < BraintreeTransparentRedirectSlice::Application
|
2
|
+
def index
|
3
|
+
render
|
4
|
+
end
|
5
|
+
|
6
|
+
def new
|
7
|
+
@credit_card = CreditCard.new
|
8
|
+
@credit_card_info = @credit_card.info
|
9
|
+
|
10
|
+
unless message[:transaction_id].nil?
|
11
|
+
@credit_card_info = Braintree::TransactionInfo.new(message[:transaction_id])
|
12
|
+
end
|
13
|
+
|
14
|
+
@gateway_request = Braintree::GatewayRequest.new(:orderid => Digest::SHA1.hexdigest(Time.now.to_s))
|
15
|
+
render
|
16
|
+
end
|
17
|
+
|
18
|
+
def new_response
|
19
|
+
@gateway_response = Braintree::GatewayResponse.validate(params)
|
20
|
+
if error = @gateway_response.error
|
21
|
+
redirect(slice_url(:new_credit_card), :message => {:notice => error, :transaction_id => params[:transactionid]})
|
22
|
+
else
|
23
|
+
session.user.credit_cards.create(:token => @gateway_response.customer_vault_id)
|
24
|
+
redirect(slice_url(:credit_cards), :message => {:notice => 'Successfully stored your card info securely.'})
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def edit(id)
|
29
|
+
fetch_credit_card(id)
|
30
|
+
@credit_card_info = @credit_card.info
|
31
|
+
@gateway_request = Braintree::GatewayRequest.new
|
32
|
+
render
|
33
|
+
end
|
34
|
+
|
35
|
+
def edit_response(id)
|
36
|
+
@gateway_response = Braintree::GatewayResponse.validate(params)
|
37
|
+
if error = @gateway_response.error
|
38
|
+
redirect(slice_url(:edit_credit_card, id), :message => {:notice => error})
|
39
|
+
else
|
40
|
+
redirect(slice_url(:credit_cards), :message => {:notice => 'Successfully updated your info in the vault.'})
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def show(id)
|
45
|
+
fetch_credit_card(id)
|
46
|
+
render
|
47
|
+
end
|
48
|
+
|
49
|
+
def destroy(id)
|
50
|
+
fetch_credit_card(id)
|
51
|
+
@gateway_request = Braintree::GatewayRequest.new
|
52
|
+
render
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class BraintreeTransparentRedirectSlice::Payments < BraintreeTransparentRedirectSlice::Application
|
2
|
+
def new(credit_card_id)
|
3
|
+
fetch_credit_card(credit_card_id)
|
4
|
+
|
5
|
+
@gateway_request = Braintree::GatewayRequest.new(:amount => '10.00')
|
6
|
+
render
|
7
|
+
end
|
8
|
+
|
9
|
+
def new_response(credit_card_id)
|
10
|
+
@gateway_response = Braintree::GatewayResponse.validate(params)
|
11
|
+
if error = @gateway_response.error
|
12
|
+
redirect(slice_url(:new_credit_card_payment), :message => {:notice => error})
|
13
|
+
else
|
14
|
+
redirect(slice_url(:credit_card, credit_card_id), :message => {:notice => 'Successfully charged your Credit Card.'})
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Merb
|
2
|
+
module BraintreeTransparentRedirectSlice
|
3
|
+
module ApplicationHelper
|
4
|
+
# @param *segments<Array[#to_s]> Path segments to append.
|
5
|
+
#
|
6
|
+
# @return <String>
|
7
|
+
# A path relative to the public directory, with added segments.
|
8
|
+
def image_path(*segments)
|
9
|
+
public_path_for(:image, *segments)
|
10
|
+
end
|
11
|
+
|
12
|
+
# @param *segments<Array[#to_s]> Path segments to append.
|
13
|
+
#
|
14
|
+
# @return <String>
|
15
|
+
# A path relative to the public directory, with added segments.
|
16
|
+
def javascript_path(*segments)
|
17
|
+
public_path_for(:javascript, *segments)
|
18
|
+
end
|
19
|
+
|
20
|
+
# @param *segments<Array[#to_s]> Path segments to append.
|
21
|
+
#
|
22
|
+
# @return <String>
|
23
|
+
# A path relative to the public directory, with added segments.
|
24
|
+
def stylesheet_path(*segments)
|
25
|
+
public_path_for(:stylesheet, *segments)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Construct a path relative to the public directory
|
29
|
+
#
|
30
|
+
# @param <Symbol> The type of component.
|
31
|
+
# @param *segments<Array[#to_s]> Path segments to append.
|
32
|
+
#
|
33
|
+
# @return <String>
|
34
|
+
# A path relative to the public directory, with added segments.
|
35
|
+
def public_path_for(type, *segments)
|
36
|
+
::BraintreeTransparentRedirectSlice.public_path_for(type, *segments)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Construct an app-level path.
|
40
|
+
#
|
41
|
+
# @param <Symbol> The type of component.
|
42
|
+
# @param *segments<Array[#to_s]> Path segments to append.
|
43
|
+
#
|
44
|
+
# @return <String>
|
45
|
+
# A path within the host application, with added segments.
|
46
|
+
def app_path_for(type, *segments)
|
47
|
+
::BraintreeTransparentRedirectSlice.app_path_for(type, *segments)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Construct a slice-level path.
|
51
|
+
#
|
52
|
+
# @param <Symbol> The type of component.
|
53
|
+
# @param *segments<Array[#to_s]> Path segments to append.
|
54
|
+
#
|
55
|
+
# @return <String>
|
56
|
+
# A path within the slice source (Gem), with added segments.
|
57
|
+
def slice_path_for(type, *segments)
|
58
|
+
::BraintreeTransparentRedirectSlice.slice_path_for(type, *segments)
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Merb
|
2
|
+
module BraintreeTransparentRedirectSlice
|
3
|
+
module CreditCardsHelper
|
4
|
+
def fetch_credit_card(id)
|
5
|
+
@credit_card = CreditCard.get(id)
|
6
|
+
raise Merb::ControllerExceptions::NotFound if @credit_card.nil?
|
7
|
+
raise Merb::ControllerExceptions::Unauthorized unless @credit_card.user_id == session.user.id
|
8
|
+
end
|
9
|
+
|
10
|
+
def braintree_date_reformatter(str)
|
11
|
+
DateTime.parse(str).strftime('%Y/%m/%d %H:%M:%S')
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end # Merb
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Braintree
|
2
|
+
class GatewayRequest
|
3
|
+
attr_accessor :orderid, :amount, :key, :key_id, :time, :response_url,
|
4
|
+
:type, :customer_vault, :customer_vault_id
|
5
|
+
|
6
|
+
attr_reader :hash
|
7
|
+
|
8
|
+
def initialize(attributes = nil)
|
9
|
+
attributes.each { |k,v| self.send("#{k}=", v) } unless attributes.nil?
|
10
|
+
self.key, self.key_id = BraintreeTransparentRedirectSlice.config[:key], BraintreeTransparentRedirectSlice.config[:key_id]
|
11
|
+
self.time = self.class.formatted_time_value
|
12
|
+
end
|
13
|
+
|
14
|
+
def hash
|
15
|
+
items = if customer_vault_id.nil?
|
16
|
+
[orderid, amount, time, BraintreeTransparentRedirectSlice.config[:key]]
|
17
|
+
else
|
18
|
+
[orderid, amount, customer_vault_id, time, BraintreeTransparentRedirectSlice.config[:key]]
|
19
|
+
end
|
20
|
+
Digest::MD5.hexdigest(items.join('|'))
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.formatted_time_value
|
24
|
+
Time.now.getutc.strftime("%Y%m%d%H%M%S")
|
25
|
+
end
|
26
|
+
|
27
|
+
def hash_attributes
|
28
|
+
{ 'orderid' => orderid, 'amount' => amount, 'key_id' => key_id,
|
29
|
+
'time' => time, 'hash' => hash, 'customer_vault_id' => customer_vault_id }
|
30
|
+
end
|
31
|
+
|
32
|
+
def post(params)
|
33
|
+
uri = Addressable::URI.parse(BraintreeTransparentRedirectSlice.config[:transact_api_url])
|
34
|
+
|
35
|
+
server = Net::HTTP.new(uri.host, 443)
|
36
|
+
server.use_ssl = true
|
37
|
+
server.read_timeout = 20
|
38
|
+
server.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
39
|
+
|
40
|
+
resp = server.start do |http|
|
41
|
+
req = Net::HTTP::Post.new(uri.path)
|
42
|
+
req.set_form_data(hash_attributes.merge(params))
|
43
|
+
http.request(req)
|
44
|
+
end
|
45
|
+
case resp
|
46
|
+
when Net::HTTPRedirection
|
47
|
+
Addressable::URI.parse(resp.header['Location'])
|
48
|
+
when Net::HTTPSuccess
|
49
|
+
resp
|
50
|
+
else
|
51
|
+
resp.error!
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'digest/md5'
|
2
|
+
|
3
|
+
module Braintree
|
4
|
+
class GatewayResponse
|
5
|
+
def self.validate(params)
|
6
|
+
new(params).validate
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(params)
|
10
|
+
@time, @hash, @amount = params.values_at(:time, :hash, :amount)
|
11
|
+
@transaction_id, @order_id, @customer_vault_id = params.values_at(:transactionid, :orderid, :customer_vault_id)
|
12
|
+
@response, @response_text = params.values_at(:response, :responsetext)
|
13
|
+
@avs_response, @cvv_response = params.values_at(:avsresponse, :cvvresponse)
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_reader :time, :hash, :amount, :error,
|
17
|
+
:transaction_id, :order_id, :customer_vault_id,
|
18
|
+
:response, :response_text,
|
19
|
+
:avs_response, :cvv_response
|
20
|
+
# :authcode
|
21
|
+
# :username
|
22
|
+
# :type
|
23
|
+
# :response_code
|
24
|
+
# :full_response
|
25
|
+
|
26
|
+
def validate
|
27
|
+
raise Merb::ControllerExceptions::Unauthorized, "Hashes did not match" unless matching_hash?
|
28
|
+
if approved?
|
29
|
+
if cvv_matches?
|
30
|
+
true
|
31
|
+
else
|
32
|
+
@error = cvv_response_message
|
33
|
+
end
|
34
|
+
else
|
35
|
+
@error = response_text
|
36
|
+
end
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
40
|
+
# The hash sent with the Gateway Response should equal a hash that can get
|
41
|
+
# generated using the key and the sent parameters.
|
42
|
+
def matching_hash?
|
43
|
+
hash == generated_hash
|
44
|
+
end
|
45
|
+
|
46
|
+
# Takes the values of the Gateway Response and generates a hash from them using
|
47
|
+
# MD5 and format listed in the documentation.
|
48
|
+
def generated_hash
|
49
|
+
items = [order_id, amount, response]
|
50
|
+
items += [transaction_id, avs_response, cvv_response]
|
51
|
+
items << customer_vault_id if customer_vault_id
|
52
|
+
items += [time, BraintreeTransparentRedirectSlice.config[:key]]
|
53
|
+
Digest::MD5.hexdigest(items.join('|'))
|
54
|
+
end
|
55
|
+
|
56
|
+
def approved?
|
57
|
+
response == "1"
|
58
|
+
end
|
59
|
+
|
60
|
+
# AVS_RESPONSE_CODES
|
61
|
+
def avs_matches?
|
62
|
+
avs_response.include?("Y")
|
63
|
+
end
|
64
|
+
|
65
|
+
# CVV_RESPONSE_CODES
|
66
|
+
def cvv_matches?
|
67
|
+
cvv_response == "M"
|
68
|
+
end
|
69
|
+
|
70
|
+
# A string representation of the response status given as a number.
|
71
|
+
def response_message
|
72
|
+
case response
|
73
|
+
when "1"
|
74
|
+
"Approved"
|
75
|
+
when "2"
|
76
|
+
"Declined"
|
77
|
+
when "3"
|
78
|
+
"Error"
|
79
|
+
else
|
80
|
+
raise "Unknown response: #{response.inspect}"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def cvv_response_message
|
85
|
+
case cvv_response
|
86
|
+
when "M"
|
87
|
+
"CVV2/CVC2 Match"
|
88
|
+
when "N"
|
89
|
+
"CVV2/CVC2 No Match"
|
90
|
+
when "P"
|
91
|
+
"Not Processed"
|
92
|
+
when "S"
|
93
|
+
"Merchant has indicated the CVV2/CVC2 is not present on card"
|
94
|
+
when "U"
|
95
|
+
"Issuer is not certified and/or has not provided Visa encryption keys"
|
96
|
+
else
|
97
|
+
#raise "Unknown CVV response: #{cvv_response.inspect}"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|