From d573a8303d94b4b7b9dcd96ec9b01a4b08fc2d3f Mon Sep 17 00:00:00 2001 From: Niall Paterson Date: Sat, 23 Nov 2013 12:27:54 +0000 Subject: [PATCH] selfstarter now works with stripe :) --- Gemfile | 1 + Gemfile.lock | 4 ++ app/assets/javascripts/application.js | 1 + app/assets/javascripts/checkout.js | 24 ++++++++ app/assets/stylesheets/checkout.css.scss | 14 +++-- app/controllers/preorder_controller.rb | 60 +++++++++---------- app/models/order.rb | 31 ++-------- app/views/layouts/application.html.erb | 5 +- app/views/preorder/checkout.html.erb | 24 ++++---- .../homepage/_middle_reserve.html.erb | 2 +- app/views/preorder/homepage/_stats.html.erb | 2 +- config/routes.rb | 12 ++-- config/settings.yml | 21 ++----- 13 files changed, 102 insertions(+), 99 deletions(-) create mode 100644 app/assets/javascripts/checkout.js diff --git a/Gemfile b/Gemfile index 803d8f49f..5a15dcc1e 100644 --- a/Gemfile +++ b/Gemfile @@ -4,6 +4,7 @@ ruby '2.0.0' gem 'rails', '4.0.0' gem 'json', '~> 1.7.7' +gem 'stripe' group :development do gem 'sqlite3' diff --git a/Gemfile.lock b/Gemfile.lock index b255e3153..31d40e8be 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -123,6 +123,9 @@ GEM activesupport (>= 3.0) sprockets (~> 2.8) sqlite3 (1.3.8) + stripe (1.8.8) + multi_json (>= 1.0.4, < 2) + rest-client (~> 1.4) thin (1.6.1) daemons (>= 1.0.9) eventmachine (>= 1.0.0) @@ -156,5 +159,6 @@ DEPENDENCIES sass-rails (~> 4.0.0) shoulda sqlite3 + stripe thin uglifier (>= 1.0.3) diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 732fd5d3d..a2faa627c 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -18,3 +18,4 @@ //= require jquery.textchange //= require preorder //= require_tree . +//= require checkout diff --git a/app/assets/javascripts/checkout.js b/app/assets/javascripts/checkout.js new file mode 100644 index 000000000..ed81f8271 --- /dev/null +++ b/app/assets/javascripts/checkout.js @@ -0,0 +1,24 @@ +$(document).ready(function () { + $('#checkout').submit(function (e) { + $('#stripe_errors').hide() + e.preventDefault(); + var _this = this + Stripe.card.createToken({ + number: $('#card_number').val().replace(/ /g, ''), + exp_month: $('#expires').val().split('/')[0], + exp_year: $('#expires').val().split('/')[1], + cvc: $('#cvv').val() + }, function (error, result) { + if (error == 200) { + $('#stripe_token').val(result.id); + console.log('stripe token added') + _this.submit(); + } + else { + //error + $('#stripe_errors').show() + return false; + } + }); + }); +}); diff --git a/app/assets/stylesheets/checkout.css.scss b/app/assets/stylesheets/checkout.css.scss index 991952126..7a8a542e8 100644 --- a/app/assets/stylesheets/checkout.css.scss +++ b/app/assets/stylesheets/checkout.css.scss @@ -14,9 +14,9 @@ } #checkout { - #email + input { - padding: 15px; + padding: 10px; border-radius: 10px; border: 1px solid #CCC; width: 350px; @@ -26,13 +26,19 @@ { border: 1px solid orange; } - #amazon_button + #stripe_button { margin-top: 5px; padding: 15px; border: none; + width: 350px; } } + #stripe_errors + { + display: none; + color: red; + } } .main_content.payment_options @@ -64,7 +70,7 @@ } } } - #amazon_button + #stripe_button { display: inline !important; } diff --git a/app/controllers/preorder_controller.rb b/app/controllers/preorder_controller.rb index 6795e6d79..024e709ae 100644 --- a/app/controllers/preorder_controller.rb +++ b/app/controllers/preorder_controller.rb @@ -1,48 +1,42 @@ class PreorderController < ApplicationController skip_before_action :verify_authenticity_token, :only => :ipn + require "stripe" + Stripe.api_key = Settings.stripe_api_key + def index end def checkout end - def prefill + def order @user = User.find_or_create_by(:email => params[:email]) - - if Settings.use_payment_options - payment_option_id = params['payment_option'] - raise Exception.new("No payment option was selected") if payment_option_id.nil? - payment_option = PaymentOption.find(payment_option_id) - price = payment_option.amount - else - price = Settings.price - end - - @order = Order.prefill!(:name => Settings.product_name, :price => price, :user_id => @user.id, :payment_option => payment_option) - - # This is where all the magic happens. We create a multi-use token with Amazon, letting us charge the user's Amazon account - # Then, if they confirm the payment, Amazon POSTs us their shipping details and phone number - # From there, we save it, and voila, we got ourselves a preorder! - port = Rails.env.production? ? "" : ":3000" - callback_url = "#{request.scheme}://#{request.host}#{port}/preorder/postfill" - redirect_to AmazonFlexPay.multi_use_pipeline(@order.uuid, callback_url, - :transaction_amount => price, - :global_amount_limit => price + Settings.charge_limit, - :collect_shipping_address => "True", - :payment_reason => Settings.payment_description) + client = Stripe::Customer.create( + :email => params[:email] + ) + card = client.cards.create(:card => params[:stripe_token]) + client.default_card = card.id + + charge = Stripe::Charge.create( + :amount => self.amount, + :currency => Settings.currency, + :customer => client.id, + :description => Settings.payment_description + ) + + raise Exception.new("Couldn't charge Card. Please try again") unless charge.paid + options = { + :user_id => @user.id, + :price => Settings.price, + :name => Settings.product_name + } + @order = Order.fill!(options) + redirect_to :action => :share, :uuid => @order.uuid end - def postfill - unless params[:callerReference].blank? - @order = Order.postfill!(params) - end - # "A" means the user cancelled the preorder before clicking "Confirm" on Amazon Payments. - if params['status'] != 'A' && @order.present? - redirect_to :action => :share, :uuid => @order.uuid - else - redirect_to root_url - end + def amount + (Settings.price * 100).to_i end def share diff --git a/app/models/order.rb b/app/models/order.rb index ba9ad4ad5..0aed49711 100644 --- a/app/models/order.rb +++ b/app/models/order.rb @@ -2,42 +2,21 @@ class Order < ActiveRecord::Base before_validation :generate_uuid!, :on => :create belongs_to :user belongs_to :payment_option - scope :completed, -> { where("token != ? OR token != ?", "", nil) } self.primary_key = 'uuid' - # This is where we create our Caller Reference for Amazon Payments, and prefill some other information. - def self.prefill!(options = {}) + # note - completed scope removed, because any entries in Order *have* to be completed ones. + + def self.fill!(options = {}) @order = Order.new @order.name = options[:name] @order.user_id = options[:user_id] @order.price = options[:price] @order.number = Order.next_order_number - @order.payment_option = options[:payment_option] if !options[:payment_option].nil? @order.save! @order end - # After authenticating with Amazon, we get the rest of the details - def self.postfill!(options = {}) - @order = Order.find_by!(:uuid => options[:callerReference]) - @order.token = options[:tokenID] - if @order.token.present? - @order.address_one = options[:addressLine1] - @order.address_two = options[:addressLine2] - @order.city = options[:city] - @order.state = options[:state] - @order.status = options[:status] - @order.zip = options[:zip] - @order.phone = options[:phoneNumber] - @order.country = options[:country] - @order.expiration = Date.parse(options[:expiry]) - @order.save! - - @order - end - end - def self.next_order_number if Order.count > 0 Order.order("number DESC").limit(1).first.number.to_i + 1 @@ -64,14 +43,14 @@ def self.percent # See what it looks like when you have some backers! Drop in a number instead of Order.count def self.backers - Order.completed.count + Order.count end def self.revenue if Settings.use_payment_options PaymentOption.joins(:orders).where("token != ? OR token != ?", "", nil).pluck('sum(amount)')[0].to_f else - Order.completed.sum(:price).to_f + Order.sum(:price).to_f end end diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 7ec9d818c..5835c4e19 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -4,7 +4,10 @@ <%= Settings.product_name %> <%= stylesheet_link_tag "application" %> - <%= javascript_include_tag "application" %> + <%= javascript_include_tag "https://js.stripe.com/v1/", "application" %> + diff --git a/app/views/preorder/checkout.html.erb b/app/views/preorder/checkout.html.erb index 0290575b1..c640d1d1b 100644 --- a/app/views/preorder/checkout.html.erb +++ b/app/views/preorder/checkout.html.erb @@ -1,31 +1,33 @@
"> -

Check out

+

Preorder

- All of your payment information will be secured and stored with Amazon Payments. If you don't have an Amazon account, simply select "I'm a new Customer" on the next page. + All of your payment information will be secured and stored with Stripe.

- <% if Settings.use_payment_options %> - Select a payment option and enter your email address below. - <% else %> - Enter your email address below. - <% end %> + Please Enter your details below.

- <%= form_tag "/preorder/prefill", :id => "checkout" do %> + <%= form_tag "/preorder/order", :id => "checkout" do %> <%= render 'preorder/payment_options' %>
<%= email_field_tag "email", nil, :placeholder => "Email address", :required => "required", :id => "email" %> - <%= hidden_field_tag "preorder", true %> - <%= hidden_field_tag "quantity", params[:quantity] %> - <%= submit_tag "Checkout", :class => "blue_button disabled", :id => "amazon_button" %> + <%= text_field_tag "card_number", nil, :placeholder => "Card Number", :required => "required", :id => "card_number" %> + <%= text_field_tag "cvv", nil, :placeholder => "CVV", :required => "required", :id => "cvv" %> + <%= text_field_tag "expires", nil, :placeholder => "Expires mm/yyyy", :required => "required", :id => "expires" %> + <%= hidden_field_tag :stripe_token %> + <%= submit_tag "Order!", :class => "blue_button", :id => "stripe_button" %>
<% end %> +
+
+ Something went wrong, please check all your details are correct +
<%= render 'preorder/checkout/sidebar' %>
diff --git a/app/views/preorder/homepage/_middle_reserve.html.erb b/app/views/preorder/homepage/_middle_reserve.html.erb index c7896067d..b2453d3d5 100644 --- a/app/views/preorder/homepage/_middle_reserve.html.erb +++ b/app/views/preorder/homepage/_middle_reserve.html.erb @@ -1,6 +1,6 @@ diff --git a/app/views/preorder/homepage/_stats.html.erb b/app/views/preorder/homepage/_stats.html.erb index e5324a66c..72a9f483f 100644 --- a/app/views/preorder/homepage/_stats.html.erb +++ b/app/views/preorder/homepage/_stats.html.erb @@ -56,7 +56,7 @@

<%= Settings.ships %>

- <%= Settings.call_to_action %> + <%= Settings.call_to_action %>

<%= Settings.price_human %>

<%= Settings.dont_give_them_a_reason_to_say_no %>

<%= like_button %> diff --git a/config/routes.rb b/config/routes.rb index 711d31518..e2315249c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,9 +1,9 @@ Selfstarter::Application.routes.draw do root :to => 'preorder#index' - match '/preorder' => 'preorder#index', :via => [:get,:post] - get 'preorder/checkout' - match '/preorder/share/:uuid' => 'preorder#share', :via => :get - match '/preorder/ipn' => 'preorder#ipn', :via => :post - match '/preorder/prefill' => 'preorder#prefill', :via => [:get,:post] - match '/preorder/postfill' => 'preorder#postfill', :via => [:get,:post] + match '/preorder' => 'preorder#index', :via => [:get,:post] + get 'preorder/order' => 'preorder#checkout' + post 'preorder/order' => 'preorder#order' + + match '/preorder/share/:uuid' => 'preorder#share', :via => :get + match '/preorder/ipn' => 'preorder#ipn', :via => :post end diff --git a/config/settings.yml b/config/settings.yml index fb9c43a72..f5b9f73b3 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -36,24 +36,13 @@ video_embed_url: "https://www.youtube.com/v/D1L3o88GKew" # NOTE: this only works for youtube video at the moment. If its not for youtube, then just leave this property blank use_video_placeholder: true -# Amazon settings -- you'll need an Amazon Payments account, sign up here --> http://bit.ly/SGksTv +# Stripe stuff. Stripe.com -# To find your access key and secret key, head over to here --> http://bit.ly/R4I4ky (Follow that guide in the Seller Central page) -amazon_access_key: "YOUR_AMAZON_ACCESS_KEY" -amazon_secret_key: "YOUR_AMAZON_SECRET_KEY" +stripe_api_key: "YOUR_STRIPE_API_KEY" +stripe_public_key: "YOUR_STRIPE_PUBLIC_KEY" +currency: "usd" # usd, eur etc price: 19.95 - -# if use_payment_options is set to true, then a set of radio buttons will be displayed with various payment options. -# There is a PaymentOption model for storing info about payment options. To set up your payment options you should -# put code in seeds.rb, then run rake db:seed -use_payment_options: false - -payment_description: "You really should change this text because people will see it on Amazon's order page!!!!!" - -# Amazon limits how much we can charge people with their Multi-Use tokens. -# You probably should add some leeway to account for international shipping -# this value will be added to the price to create a charge limit -charge_limit: 25.00 +payment_description: "You really should change this text because people will see it on their list of transactions!" # Stats settings