Permalink
Browse files

Create credit cards for customers through TR

  • Loading branch information...
1 parent 0eacad7 commit 2fe003f36b11435780be9e856175c7140c520e2b @wonnage wonnage committed with Gabe Berke-Williams Jul 30, 2012
@@ -7,6 +7,21 @@ def initialize(credit_card_hash_from_params, options)
set_expiration_month_and_year
end
+ def create
+ if (customer = FakeBraintree.registry.customers[@hash['customer_id']])
+ if token.nil?
+ @hash['token'] = generate_token
+ end
+ FakeBraintree.registry.credit_cards[token] = @hash
+ customer['credit_cards'] << @hash
+
+ update_default_card
+ response_for_updated_card
+ else
+ response_for_invalid_card
+ end
+ end
+
def update
if credit_card_exists_in_registry?
update_existing_credit_card
@@ -24,6 +39,18 @@ def to_xml
def update_existing_credit_card
@hash = credit_card_from_registry.merge!(@hash)
+ update_default_card
+ end
+
+ # When updating a card that has 'default' set to true, make sure
+ # only one card has the flag.
+ def update_default_card
+ if @hash['default']
+ FakeBraintree.registry.customers[@hash['customer_id']]['credit_cards'].each do |card|
+ card['default'] = false
+ end
+ @hash['default'] = true
+ end
end
def response_for_updated_card
@@ -42,6 +69,10 @@ def response_for_card_not_found
gzipped_response(404, FakeBraintree.failure_response.to_xml(:root => 'api_error_response'))
end
+ def response_for_invalid_card
+ gzipped_response(422, FakeBraintree.failure_response.merge('params' => {:credit_card => @hash}).to_xml(:root => 'api_error_response'))
+ end
+
def expiration_month
expiration_date_parts[0]
end
@@ -53,7 +84,9 @@ def expiration_year
def set_up_credit_card(credit_card_hash_from_params, options)
@hash = {
"token" => options[:token],
- "merchant_id" => options[:merchant_id]
+ "merchant_id" => options[:merchant_id],
+ "customer_id" => options[:customer_id],
+ "default" => options[:make_default]
}.merge(credit_card_hash_from_params)
end
@@ -67,6 +100,10 @@ def set_expiration_month_and_year
end
end
+ def generate_token
+ md5("#{@hash['number']}#{@hash['merchant_id']}")
+ end
+
def token
@hash['token']
end
@@ -6,18 +6,28 @@ class Redirect
def initialize(params, merchant_id)
hash, query = *params[:tr_data].split("|", 2)
- @transparent_data = Rack::Utils.parse_query(query)
+ @transparent_data = Rack::Utils.parse_nested_query(query)
@merchant_id = merchant_id
@id = create_id(@merchant_id)
@params = params
+ @kind = @transparent_data['kind']
end
def url
uri.to_s
end
def confirm
- Customer.new(@params["customer"], {:merchant_id => @merchant_id}).create
+ if @kind == 'create_customer'
+ Customer.new(@params["customer"], {:merchant_id => @merchant_id}).create
+ elsif @kind == 'create_payment_method'
+ options = {:merchant_id => @merchant_id}
+ if more_opts = (@transparent_data['credit_card'] && @transparent_data['credit_card'].delete('options'))
+ options.merge!(more_opts)
+ end
+ options.symbolize_keys!
+ CreditCard.new(@params['credit_card'].merge(@transparent_data['credit_card']), options).create
+ end
end
private
@@ -27,7 +37,7 @@ def uri
end
def base_query
- "http_status=200&id=#{@id}&kind=create_customer"
+ "http_status=200&id=#{@id}&kind=#{@kind}"
end
def hash(string)
@@ -80,7 +80,11 @@ def hash_from_request_body_with_key(request, key)
# Braintree::CreditCard.find
get "/merchants/:merchant_id/payment_methods/:credit_card_token" do
credit_card = FakeBraintree.registry.credit_cards[params[:credit_card_token]]
- gzipped_response(200, credit_card.to_xml(:root => "credit_card"))
+ if credit_card
+ gzipped_response(200, credit_card.to_xml(:root => "credit_card"))
+ else
+ gzipped_response(404, {})
+ end
end
post "/merchants/:merchant_id/payment_methods" do
@@ -105,6 +109,14 @@ def hash_from_request_body_with_key(request, key)
CreditCard.new(updates, options).update
end
+ # Braintree::CreditCard.create
+ post "/merchants/:merchant_id/payment_methods" do
+ credit_card_hash = hash_from_request_body_with_key(request, "credit_card")
+ options = {:token => params[:credit_card_token], :merchant_id => params[:merchant_id]}
+ options.merge!(credit_card_hash.delete('options')).symbolize_keys! if credit_card_hash['options']
+ CreditCard.new(credit_card_hash, options).create
+ end
+
# Braintree::Transaction.sale
# Braintree::CreditCard.sale
post "/merchants/:merchant_id/transactions" do
@@ -35,6 +35,85 @@
end
end
+describe "Braintree::CreditCard.create" do
+ it 'fails to create a credit card without a customer' do
+ result = Braintree::CreditCard.create(
+ :customer_id => 'fail',
+ :number => '4111111111111111',
+ :cvv => '123',
+ :token => 'token',
+ :expiration_date => '07/2020',
+ :billing_address => {
+ :postal_code => '94110'
+ },
+ :options => {
+ :make_default => true
+ }
+ )
+ result.should_not be_success
+ expect { Braintree::CreditCard.find('token') }.to raise_exception Braintree::NotFoundError
+ end
+
+ context 'with a customer' do
+ before do
+ @customer = Braintree::Customer.create.customer
+ end
+ it 'successfully creates a credit card' do
+ result = Braintree::CreditCard.create(
+ :customer_id => @customer.id,
+ :number => '4111111111111111',
+ :cvv => '123',
+ :token => 'token',
+ :expiration_date => '07/2020',
+ :billing_address => {
+ :postal_code => '94110'
+ },
+ :options => {
+ :make_default => true
+ }
+ )
+ result.should be_success
+ Braintree::Customer.find(@customer.id).credit_cards.last.token.should == 'token'
+ Braintree::Customer.find(@customer.id).credit_cards.last.default?.should be_true
+ end
+
+ it 'only allows one credit card to be default' do
+ result = Braintree::CreditCard.create(
+ :customer_id => @customer.id,
+ :number => '4111111111111111',
+ :cvv => '123',
+ :token => 'token',
+ :expiration_date => '07/2020',
+ :billing_address => {
+ :postal_code => '94110'
+ },
+ :options => {
+ :make_default => true
+ }
+ )
+ result.should be_success
+ result = Braintree::CreditCard.create(
+ :customer_id => @customer.id,
+ :number => '4111111111111111',
+ :cvv => '123',
+ :token => 'token',
+ :expiration_date => '07/2020',
+ :billing_address => {
+ :postal_code => '94110'
+ },
+ :options => {
+ :make_default => true
+ }
+ )
+ result.should be_success
+ # Reload the customer
+ @customer = Braintree::Customer.find(@customer.id)
+ @customer.credit_cards.select {|c| c.default?}.length.should == 1
+ @customer.credit_cards.length.should == 2
+ end
+ end
+end
+
describe "Braintree::CreditCard.update" do
it "successfully updates the credit card" do
new_expiration_date = "08/2012"
@@ -5,7 +5,7 @@
it "returns a URL that will redirect with a token for the specified request" do
redirect_url = "http://example.com/redirect_path"
- response = post_transparent_redirect(:redirect_url => redirect_url, :customer => build_customer_hash)
+ response = post_transparent_redirect(:create_customer_data, :redirect_url => redirect_url, :customer => build_customer_hash)
response.code.should == "303"
response["Location"].should =~ %r{http://example\.com/redirect_path}
@@ -22,18 +22,37 @@
end
context "Braintree::TransparentRedirect.confirm" do
- it "confirms and runs the specified request" do
- number = "4111111111111111"
- customer_hash = build_customer_hash(:credit_card => { :number => number })
- response = post_transparent_redirect(:customer => customer_hash)
- query = parse_query(response)
+ describe "Creating customers" do
+ it "confirms and runs the specified request" do
+ number = "4111111111111111"
+ customer_hash = build_customer_hash(:credit_card => { :number => number })
+ response = post_transparent_redirect(:create_customer_data, :customer => customer_hash)
+ query = parse_query(response)
- result = Braintree::TransparentRedirect.confirm(query)
+ result = Braintree::TransparentRedirect.confirm(query)
- result.should be_success
+ result.should be_success
- customer = Braintree::Customer.find(result.customer.id)
- customer.credit_cards.first.last_4.should == "1111"
+ customer = Braintree::Customer.find(result.customer.id)
+ customer.credit_cards.first.last_4.should == "1111"
+ end
+ end
+
+ describe "Creating credit cards" do
+ it "confirms and runs the specified request" do
+ customer = create_customer.customer
+ number = "4111111111111337"
+ credit_card_hash = build_credit_card_hash({ :number => number, :customer_id => customer.id})
+ response = post_transparent_redirect(:create_credit_card_data, :credit_card => credit_card_hash)
+ query = parse_query(response)
+
+ result = Braintree::TransparentRedirect.confirm(query)
+
+ result.should be_success
+
+ customer = Braintree::Customer.find(customer.id)
+ customer.credit_cards.first.last_4.should == "1111"
+ end
end
end
@@ -47,10 +66,25 @@ def build_customer_hash(options = {})
}
end
- def post_transparent_redirect(data)
+ def build_credit_card_hash(options = {})
+ {
+ :number => "4111111111111111",
+ :expiration_date => "4/2015",
+ :cardholder_name => "Susie Spender",
+ :cvv => '123',
+ :billing_address => {
+ :street_address => "123 Sesame Street",
+ :locality => "San Francisco",
+ :region => "CA",
+ :postal_code => "94110"
+ }
+ }.update(options || {})
+ end
+
+ def post_transparent_redirect(type, data)
params = data.dup
redirect_url = params.delete(:redirect_url) || "http://example.com/redirect_path"
- params[:tr_data] = Braintree::TransparentRedirect.create_customer_data(:redirect_url => redirect_url)
+ params[:tr_data] = Braintree::TransparentRedirect.send(type, {:redirect_url => redirect_url}.merge(params))
post_transparent_redirect_params(params)
end

0 comments on commit 2fe003f

Please sign in to comment.