Skip to content

Commit

Permalink
DECK ORDERS!
Browse files Browse the repository at this point in the history
  • Loading branch information
tjhorner committed Jun 13, 2016
1 parent 4017fd0 commit e7fff77
Show file tree
Hide file tree
Showing 30 changed files with 739 additions and 1 deletion.
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ gem 'stripe'
gem 'validates_email_format_of'
# for 2fa
gem 'rotp'
# shipping costs :}
gem 'active_shipping'

# Use ActiveModel has_secure_password
# gem 'bcrypt', '~> 3.1.7'
Expand Down
10 changes: 10 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@ GEM
erubis (~> 2.7.0)
rails-dom-testing (~> 1.0, >= 1.0.5)
rails-html-sanitizer (~> 1.0, >= 1.0.2)
active_shipping (1.7.3)
active_utils (~> 3.2.0)
activesupport (>= 3.2, < 5.0.0)
nokogiri (>= 1.6)
quantified (~> 1.0.1)
active_utils (3.2.0)
activesupport (>= 3.2)
i18n
activejob (4.2.6)
activesupport (= 4.2.6)
globalid (>= 0.3.0)
Expand Down Expand Up @@ -88,6 +96,7 @@ GEM
nokogiri (1.6.7.2)
mini_portile2 (~> 2.0.0.rc2)
pg (0.18.4)
quantified (1.0.1)
rack (1.6.4)
rack-pjax (0.8.0)
nokogiri (~> 1.5)
Expand Down Expand Up @@ -182,6 +191,7 @@ PLATFORMS
ruby

DEPENDENCIES
active_shipping
bcrypt
byebug
coffee-rails (~> 4.1.0)
Expand Down
3 changes: 3 additions & 0 deletions app/assets/javascripts/deck_orders.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
25 changes: 25 additions & 0 deletions app/assets/stylesheets/deck_orders.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
.order-details{
width: 100%;

th{
text-align: left;
}

th, td{
padding: 7px;
border-bottom: 1px solid black;
}
}

.order-button{
text-align: center;
margin-top: 15px;
}

.address{
input{
width: 100%;
margin-bottom: 5px;
padding: 5px;
}
}
31 changes: 31 additions & 0 deletions app/assets/stylesheets/responsive_grid_system.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/* SECTIONS */
.section {
clear: both;
padding: 0px;
margin: 0px;
}

/* COLUMN SETUP */
.col {
display: block;
float:left;
margin: 1% 0 1% 1.6%;
}
.col:first-child { margin-left: 0; }

/* GROUPING */
.group:before,
.group:after { content:""; display:table; }
.group:after { clear:both;}
.group { zoom:1; /* For IE 6/7 */ }

/* GRID OF THREE */
.span_3_of_3 { width: 100%; }
.span_2_of_3 { width: 66.13%; }
.span_1_of_3 { width: 32.26%; }

/* GO FULL WIDTH BELOW 480 PIXELS */
@media only screen and (max-width: 480px) {
.col { margin: 1% 0 1% 0%; }
.span_3_of_3, .span_2_of_3, .span_1_of_3 { width: 100%; }
}
130 changes: 130 additions & 0 deletions app/controllers/deck_orders_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
class DeckOrdersController < ApplicationController
before_filter :validate_logged_in
skip_before_action :verify_authenticity_token

def show
@order = DeckOrder.find(params[:id])
unless @order.user == current_user then redirect_to root_path end
@title = "Order \##{@order.id}"
end

def new
@deck = Deck.find(params[:deck])
@title = "Order Deck"

if current_user.stripe_customer_id
@customer = current_user.stripe_customer
end
end

def quote
@deck = Deck.find(params[:address][:deck_id])
unless @deck.user == current_user then redirect_to root_path end
@title = "Order Deck"

shipping = DeckOrder.calculate_shipping({
:country => params[:address][:country],
:state => params[:address][:state],
:city => params[:address][:city],
:zip => params[:address][:zip]
})

@quote = {
:deck_price => '%.2f' % @deck.price,
:shipping_price => '%.2f' % shipping[1],
:shipping_service => shipping[0],
:total_price => '%.2f' % (@deck.price + shipping[1]),
:total_price_cents => ((@deck.price + shipping[1]) * 100).to_i,
:city => "#{params[:address][:city]}, #{params[:address][:state]}, #{params[:address][:country]}",
:shipping_name => params[:address][:name],
:shipping_zip => params[:address][:zip],
:shipping_line1 => params[:address][:line1],
:shipping_line2 => params[:address][:line2],
:address => params[:address]
}

render "new"
end

def order
deck = Deck.find(params[:order][:deck_id])
unless deck.user == current_user then redirect_to root_path end

# re-calculate everything to make sure the client isn't lying to us
shipping = DeckOrder.calculate_shipping({
:country => params[:order][:address_country],
:state => params[:order][:address_state],
:city => params[:order][:address_city],
:zip => params[:order][:address_zip]
})

total_price = ((shipping[1] + deck.price) * 100).to_i

token = params[:stripeToken]

unless current_user.stripe_customer
customer = Stripe::Customer.create(
:description => current_user.name,
:email => current_user.email,
:metadata => {
:user_id => current_user.id
},
:source => token,
:shipping => {
:name => params[:order][:address_name],
:address => {
:line1 => params[:order][:address_line1],
:line2 => params[:order][:address_line2],
:country => params[:order][:address_country],
:state => params[:order][:address_state],
:city => params[:order][:address_city],
:postal_code => params[:order][:address_zip]
}
}
)

current_user.update(:stripe_customer_id => customer["id"])
else
customer = current_user.stripe_customer
end

begin
charge = Stripe::Charge.create(
:amount => total_price,
:currency => "usd",
:customer => customer["id"],
:receipt_email => current_user.email,
:description => "Custom Deck Print for #{current_user.email}",
:metadata => {
:user_id => current_user.id
}
)

order = DeckOrder.create({
:deck => deck,
:user => current_user,
:shipping_name => params[:order][:address_name],
:shipping_line_1 => params[:order][:address_line1],
:shipping_line_2 => params[:order][:address_line2],
:shipping_country => params[:order][:address_country],
:shipping_city => params[:order][:address_city],
:shipping_state => params[:order][:address_state],
:shipping_zip => params[:order][:address_zip],
:base_price => deck.price,
:shipping_price => shipping[1],
:stripe_charge_id => charge["id"]
})

charge = Stripe::Charge.retrieve(charge["id"])
charge.metadata = {
:user_id => current_user.id,
:order_id => order.id
}
charge.save

redirect_to order
rescue Stripe::CardError => e
render plain: "There was an error processing your card. Please go back and try again."
end
end
end
2 changes: 2 additions & 0 deletions app/helpers/deck_orders_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
module DeckOrdersHelper
end
49 changes: 49 additions & 0 deletions app/models/deck.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,55 @@ def initialize_cards
self.white_cards ||= []
end

def total_cards
self.black_cards.count + self.white_cards.count
end

def base_price
total_cards = self.total_cards

# THERE MUST BE A CLEANER WAY TO DO THIS.
if total_cards <= 18
6.00
elsif total_cards <= 36
9.60
elsif total_cards <= 54
12.00
elsif total_cards <= 72
16.00
elsif total_cards <= 90
20.00
elsif total_cards <= 108
24.00
elsif total_cards <= 126
28.00
elsif total_cards <= 144
32.00
elsif total_cards <= 162
36.00
elsif total_cards <= 180
40.00
elsif total_cards <= 198
44.00
elsif total_cards <= 216
48.00
elsif total_cards <= 234
52.00
elsif total_cards <= 396
83.00
elsif total_cards <= 504
103.60
elsif total_cards <= 612
122.40
else
130.00
end
end

def price
self.total_cards * 0.02 + self.base_price
end

def self.validate_black_cards(cards)
validated_cards = []

Expand Down
35 changes: 35 additions & 0 deletions app/models/deck_order.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
class DeckOrder < ActiveRecord::Base
belongs_to :user
belongs_to :deck
after_initialize :default_values

def default_values
self.shipped ||= false
end

def tracking_url
"https://wwwapps.ups.com/WebTracking/track?track=yes&trackNums=#{self.tracking_number}&loc=en_us"
end

def self.calculate_shipping(address)
package = ActiveShipping::Package.new(16, [5, 5, 5], units: :imperial)

origin = ActiveShipping::Location.new({
country: $ship_from_country,
state: $ship_from_state,
city: $ship_from_city,
zip: $ship_from_zip
})

dest = ActiveShipping::Location.new({
country: address[:country],
state: address[:state],
city: address[:city],
zip: address[:zip]
})

# format it properly :)
rate = $ups.find_rates(origin, dest, package).rates.sort_by(&:price)[0]
[rate.service_name, rate.price / 100.00]
end
end
8 changes: 8 additions & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ def default_values
self.custom_badges ||= []
end

def stripe_customer
if self.stripe_customer_id && self.stripe_customer_id != ""
Stripe::Customer.retrieve(self.stripe_customer_id)
else
nil
end
end

def deck_limit
self.premium ? 100 : 3
end
Expand Down
12 changes: 12 additions & 0 deletions app/views/deck_orders/index.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<h1>Order a Deck</h1>

<p>
You can have your deck printed in the same size as CAH cards and shipped to
your doorstep! To start, click the deck you would like to purchase:
</p>

<div class="decks">
<% current_user.decks.order("id DESC").each do |deck| %>
<%= render partial: "decks/module_order", locals: { deck: deck } %>
<% end %>
</div>
Loading

0 comments on commit e7fff77

Please sign in to comment.