Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

have slightly skinnier controllers now due to some gateway response r…

…efactorings
  • Loading branch information...
commit 8992c8488c35f8ed211ca529395a82b080372afb 1 parent 23ddf73
@atmos authored
View
27 app/controllers/credit_cards.rb
@@ -16,18 +16,12 @@ def new
end
def new_response
- @gateway_response = Braintree::GatewayResponse.new(params)
- raise Unauthorized unless @gateway_response.is_valid?
- case @gateway_response.response_status
- when 'approved'
- if @gateway_response.cvv_matches?
- session.user.credit_cards.create(:token => @gateway_response.customer_vault_id)
- redirect(slice_url(:credit_cards), :message => {:notice => 'Successfully stored your card info securely.'})
- else
- redirect(slice_url(:new_credit_card), :message => {:notice => @gateway_response.cvvresponse_string, :transaction_id => params['transactionid']})
- end
+ @gateway_response = Braintree::GatewayResponse.validate(params)
+ if error = @gateway_response.error
+ redirect(slice_url(:new_credit_card), :message => {:notice => error, :transaction_id => params[:transactionid]})
else
- redirect(slice_url(:new_credit_card), :message => {:notice => @gateway_response.responsetext, :transaction_id => params['transactionid']})
+ session.user.credit_cards.create(:token => @gateway_response.customer_vault_id)
+ redirect(slice_url(:credit_cards), :message => {:notice => 'Successfully stored your card info securely.'})
end
end
@@ -39,14 +33,11 @@ def edit(id)
end
def edit_response(id)
- @gateway_response = Braintree::GatewayResponse.new(params.reject { |k,v| k == 'id' })
- raise Unauthorized unless @gateway_response.is_valid?
- case @gateway_response.response_status
- when 'approved'
- redirect(slice_url(:credit_cards), :message => {:notice => 'Successfully updated your info in the vault.'})
+ @gateway_response = Braintree::GatewayResponse.validate(params)
+ if error = @gateway_response.error
+ redirect(slice_url(:edit_credit_card, id), :message => {:notice => error})
else
- fetch_credit_card(id)
- redirect(slice_url(:edit_credit_card, @credit_card.id), :message => {:notice => @gateway_response.responsetext})
+ redirect(slice_url(:credit_cards), :message => {:notice => 'Successfully updated your info in the vault.'})
end
end
View
11 app/controllers/payments.rb
@@ -7,14 +7,11 @@ def new(credit_card_id)
end
def new_response(credit_card_id)
- @gateway_response = Braintree::GatewayResponse.new(params.reject { |k,v| k == 'credit_card_id' })
- raise Unauthorized unless @gateway_response.is_valid?
- case @gateway_response.response_status
- when 'approved'
- fetch_credit_card(credit_card_id)
- redirect(slice_url(:credit_card, @credit_card.id), :message => {:notice => 'Successfully charged your Credit Card.'})
+ @gateway_response = Braintree::GatewayResponse.validate(params)
+ if error = @gateway_response.error
+ redirect(slice_url(:new_credit_card_payment), :message => {:notice => error})
else
- redirect(slice_url(:new_credit_card_payment), :message => {:notice => @gateway_response.responsetext})
+ redirect(slice_url(:credit_card, credit_card_id), :message => {:notice => 'Successfully charged your Credit Card.'})
end
end
end
View
90 app/models/braintree/gateway_response.rb
@@ -1,60 +1,88 @@
+require 'digest/md5'
+
module Braintree
class GatewayResponse
+ def self.validate(params)
+ new(params).validate
+ end
- attr_accessor :response, :responsetext, :response_code, :full_response,
- :cvvresponse, :avsresponse, :time, :orderid,
- :amount, :transactionid, :authcode, :username,
- :customer_vault_id, :type, :hash, :response_status
-
- def initialize(attributes = nil)
- # FIXME: there is a much easier way to do this.
- attributes.delete_if { |param, value| param == "format" }
- attributes.delete_if { |param, value| param == "action" }
- attributes.delete_if { |param, value| param == "controller" }
- attributes.each { |k,v| self.send("#{k}=", v) } if attributes.any?
+ def initialize(params)
+ @time, @hash, @amount = params.values_at(:time, :hash, :amount)
+ @transaction_id, @order_id, @customer_vault_id = params.values_at(:transactionid, :orderid, :customer_vault_id)
+ @response, @response_text = params.values_at(:response, :responsetext)
+ @avs_response, @cvv_response = params.values_at(:avsresponse, :cvvresponse)
end
- # A string representation of the response status given as a number.
- def response_status
- case self.response
- when "1"
- "approved"
- when "2"
- "declined"
- when "3"
- "error"
+ attr_reader :time, :hash, :amount, :error,
+ :transaction_id, :order_id, :customer_vault_id,
+ :response, :response_text,
+ :avs_response, :cvv_response
+# :authcode
+# :username
+# :type
+# :response_code
+# :full_response
+
+ def validate
+ raise Merb::ControllerExceptions::Unauthorized, "Hashes did not match" unless matching_hash?
+ if approved?
+ if cvv_matches?
+ true
+ else
+ @error = cvv_response_message
+ end
+ else
+ @error = response_text
end
+ self
end
# The hash sent with the Gateway Response should equal a hash that can get
# generated using the key and the sent parameters.
- def is_valid?
+ def matching_hash?
hash == generated_hash
end
# Takes the values of the Gateway Response and generates a hash from them using
# MD5 and format listed in the documentation.
def generated_hash
- items = if customer_vault_id.nil?
- [orderid, amount, response, transactionid, avsresponse, cvvresponse, time, BraintreeTransparentRedirectSlice.config[:key]]
- else
- [orderid, amount, response, transactionid, avsresponse, cvvresponse, customer_vault_id, time, BraintreeTransparentRedirectSlice.config[:key]]
- end
+ items = [order_id, amount, response]
+ items += [transaction_id, avs_response, cvv_response]
+ items << customer_vault_id if customer_vault_id
+ items += [time, BraintreeTransparentRedirectSlice.config[:key]]
Digest::MD5.hexdigest(items.join('|'))
end
+ def approved?
+ response == "1"
+ end
+
# AVS_RESPONSE_CODES
def avs_matches?
- self.avsresponse.include?("Y")
+ avs_response.include?("Y")
end
# CVV_RESPONSE_CODES
def cvv_matches?
- self.cvvresponse == "M" ? true : false
+ cvv_response == "M"
end
- def cvvresponse_string
- case self.cvvresponse
+ # A string representation of the response status given as a number.
+ def response_message
+ case response
+ when "1"
+ "Approved"
+ when "2"
+ "Declined"
+ when "3"
+ "Error"
+ else
+ raise "Unknown response: #{response.inspect}"
+ end
+ end
+
+ def cvv_response_message
+ case cvv_response
when "M"
"CVV2/CVC2 Match"
when "N"
@@ -65,6 +93,8 @@ def cvvresponse_string
"Merchant has indicated the CVV2/CVC2 is not present on card"
when "U"
"Issuer is not certified and/or has not provided Visa encryption keys"
+ else
+ #raise "Unknown CVV response: #{cvv_response.inspect}"
end
end
end
View
2  app/models/credit_card.rb
@@ -11,7 +11,7 @@ class CreditCard
def info
@info ||= CreditCardInfo.new(token)
end
-
+
def invoices
@invoices ||= CreditCardInvoice.parse(self)
end
View
6 public/javascripts/master.js
@@ -0,0 +1,6 @@
+// Common JavaScript code across your application goes here.
+$(function() {
+ jQuery(document).ready(function($) {
+ $('#add_card_form').validate();
+ });
+});
View
155 public/stylesheets/master.css
@@ -1,2 +1,153 @@
-html, body { margin: 0; padding: 0; }
-#container { width: 800px; margin: 4em auto; padding: 4em 4em 6em 4em; background: #DDDDDD; }
+html, body {
+ font-family: Arial, Verdana, sans-serif;
+ font-size: 12px;
+ background-color: #fff;
+ margin: 0;
+ padding: 0;
+}
+* {
+ margin: 0px;
+ padding: 0px;
+ text-decoration: none;
+}
+html {
+ height: 100%;
+ margin-bottom: 1px;
+}
+#container {
+ width: 80%;
+ text-align: left;
+ background-color: #fff;
+ margin-right: auto;
+ margin-left: auto;
+}
+#header-container {
+ width: 100%;
+ padding-top: 15px;
+}
+#header-container h1, #header-container h2 {
+ margin-left: 6px;
+ margin-bottom: 6px;
+}
+.spacer {
+ width: 100%;
+ height: 15px;
+}
+hr {
+ border: 0px;
+ color: #ccc;
+ background-color: #cdcdcd;
+ height: 1px;
+ width: 100%;
+ text-align: left;
+}
+h1 {
+ font-size: 28px;
+ color: #c55;
+ background-color: #fff;
+ font-family: Arial, Verdana, sans-serif;
+ font-weight: 300;
+}
+h2 {
+ font-size: 15px;
+ color: #999;
+ font-family: Arial, Verdana, sans-serif;
+ font-weight: 300;
+ background-color: #fff;
+}
+h3 {
+ color: #4d9b12;
+ font-size: 15px;
+ text-align: left;
+ font-weight: 300;
+ padding: 5px;
+ margin-top: 5px;
+}
+
+#left-container {
+ float: left;
+ width: 250px;
+ background-color: #FFFFFF;
+ color: black;
+}
+
+#left-container ul {
+ list-style-type: none;
+ font-size: 1.4em;
+ padding-left: 15px;
+}
+
+#left-container h3 {
+ color: #c55;
+}
+
+#main-container {
+ margin: 5px 5px 5px 260px;
+ padding: 15px;
+ border-left: 1px solid silver;
+ min-height: 400px;
+}
+p {
+ color: #000;
+ background-color: #fff;
+ line-height: 20px;
+ padding: 5px;
+}
+a {
+ color: #4d9b12;
+ background-color: #fff;
+ text-decoration: none;
+}
+a:hover {
+ color: #4d9b12;
+ background-color: #fff;
+ text-decoration: underline;
+}
+#footer-container {
+ clear: both;
+ font-size: 12px;
+ font-family: Verdana, Arial, sans-serif;
+}
+.right {
+ float: right;
+ font-size: 100%;
+ margin-top: 5px;
+ color: #999;
+ background-color: #fff;
+}
+.left {
+ float: left;
+ font-size: 100%;
+ margin-top: 5px;
+ color: #999;
+ background-color: #fff;
+}
+#main-container ul {
+ margin-left: 3.0em;
+}
+fieldset {
+ padding: 7px;
+}
+input {
+ display: block;
+ margin: 2px;
+}
+table {
+ margin: 3px;
+ border: 1px solid #000;
+}
+table tr {
+ border: none;
+ padding: 0;
+ margin: 0;
+}
+table th {
+ border: none;
+ padding: 0px 7px;
+ margin: 0;
+}
+
+table td {
+ padding: 1px 7px;
+ border-top: 1px solid #000;
+}
Please sign in to comment.
Something went wrong with that request. Please try again.