* wip
This commit is contained in:
parent
137c6faedc
commit
661c4ed446
|
|
@ -64,7 +64,7 @@ ActiveAdmin.register JamRuby::JamTrackRight, :as => 'JamTrackRights' do
|
|||
|
||||
begin
|
||||
client.find_or_create_account(user, billing_info)
|
||||
client.place_order(user, jam_track)
|
||||
client.place_order(user, jam_track, nil)
|
||||
rescue RecurlyClientError=>x
|
||||
redirect_to admin_jam_track_rights_path, notice: "Could not order #{jam_track} for #{user.to_s}: #{x.errors.inspect}"
|
||||
else
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ FactoryGirl.define do
|
|||
state "NC"
|
||||
country "US"
|
||||
terms_of_service true
|
||||
resue_card true
|
||||
reuse_card true
|
||||
|
||||
|
||||
factory :admin do
|
||||
|
|
|
|||
|
|
@ -262,4 +262,4 @@ jam_track_importer.sql
|
|||
jam_track_pro_licensing_update.sql
|
||||
jam_track_redeemed.sql
|
||||
shopping_cart_anonymous.sql
|
||||
user_reuse_card.sql
|
||||
user_reuse_card_and_reedem.sql
|
||||
|
|
@ -1 +0,0 @@
|
|||
ALTER TABLE users ADD COLUMN reuse_card BOOLEAN DEFAULT TRUE NOT NULL;
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
ALTER TABLE users ADD COLUMN reuse_card BOOLEAN DEFAULT TRUE NOT NULL;
|
||||
ALTER TABLE users ADD COLUMN has_redeemable_jamtrack BOOLEAN DEFAULT TRUE NOT NULL;
|
||||
ALTER TABLE shopping_carts ADD COLUMN marked_for_redeem INTEGER DEFAULT 0 NOT NULL;
|
||||
|
|
@ -21,5 +21,9 @@ module JamRuby
|
|||
def admin
|
||||
false
|
||||
end
|
||||
|
||||
def has_redeemable_jamtrack
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -141,12 +141,14 @@ module JamRuby
|
|||
|
||||
recording.recorded_tracks.each do |recorded_track|
|
||||
manifest["files"] << { "filename" => recorded_track.sign_url(one_day), "codec" => "vorbis", "offset" => 0 }
|
||||
mix_params << { "level" => 1.0, "balance" => 0 }
|
||||
mix_params << { "level" => 100, "balance" => 0 }
|
||||
# change to 1.0 when ready to deploy new audiomixer
|
||||
end
|
||||
|
||||
recording.recorded_backing_tracks.each do |recorded_backing_track|
|
||||
manifest["files"] << { "filename" => recorded_backing_track.sign_url(one_day), "codec" => "vorbis", "offset" => 0 }
|
||||
mix_params << { "level" => 1.0, "balance" => 0 }
|
||||
mix_params << { "level" => 100, "balance" => 0 }
|
||||
# change to 1.0 when ready to deploy new audiomixer
|
||||
end
|
||||
|
||||
recording.recorded_jam_track_tracks.each do |recorded_jam_track_track|
|
||||
|
|
|
|||
|
|
@ -8,19 +8,32 @@ module JamRuby
|
|||
validates :cart_id, presence: true
|
||||
validates :cart_type, presence: true
|
||||
validates :cart_class_name, presence: true
|
||||
validates :marked_for_redeem, :inclusion => {:in => [true, false]}
|
||||
|
||||
default_scope order('created_at DESC')
|
||||
|
||||
def product_info
|
||||
product = self.cart_product
|
||||
{name: product.name, price: product.price, product_id: cart_id} unless product.nil?
|
||||
{name: product.name, price: product.price, product_id: cart_id, plan_code: product.plan_code, total_price: total_price(product), quantity: quantity, marked_for_redeem:marked_for_redeem} unless product.nil?
|
||||
end
|
||||
|
||||
# multiply (quantity - redeemable) by price
|
||||
def total_price(product)
|
||||
(quantity - marked_for_redeem) * product.price
|
||||
end
|
||||
def cart_product
|
||||
self.cart_class_name.classify.constantize.find_by_id self.cart_id unless self.cart_class_name.blank?
|
||||
end
|
||||
|
||||
def self.create user, product, quantity = 1
|
||||
def redeem(mark_redeem)
|
||||
self.marked_for_redeem = mark_redeem ? 1 : 0
|
||||
end
|
||||
|
||||
def free?
|
||||
marked_for_redeem == quantity
|
||||
end
|
||||
|
||||
def self.create user, product, quantity = 1, mark_redeem = false
|
||||
cart = ShoppingCart.new
|
||||
if user.is_a?(User)
|
||||
cart.user = user
|
||||
|
|
@ -32,8 +45,27 @@ module JamRuby
|
|||
cart.cart_class_name = product.class.name
|
||||
cart.cart_id = product.id
|
||||
cart.quantity = quantity
|
||||
cart.redeem(mark_redeem)
|
||||
cart.save
|
||||
cart
|
||||
end
|
||||
|
||||
# if the user has a redeemable jam_track still on their account, then also check if any shopping carts have already been marked.
|
||||
# if no shpping carts have been marked, then mark it redeemable
|
||||
# should be wrapped in a TRANSACTION
|
||||
def self.user_has_redeemable_jam_track?(any_user)
|
||||
mark_redeem = false
|
||||
if APP_CONFIG.one_free_jamtrack_per_user && any_user.has_redeemable_jamtrack
|
||||
mark_redeem = true # start out assuming we can redeem...
|
||||
shopping_carts.each do |shopping_cart|
|
||||
# but if we find any shopping cart item already marked for redeem, then back out of mark_redeem=true
|
||||
if shopping_cart.cart_type == product.class::PRODUCT_TYPE && shopping_cart.marked_for_redeem > 0
|
||||
mark_redeem = false
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
mark_redeem
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -172,6 +172,7 @@ module JamRuby
|
|||
|
||||
validates :terms_of_service, :acceptance => {:accept => true, :on => :create, :allow_nil => false }
|
||||
validates :reuse_card, :inclusion => {:in => [true, false]}
|
||||
validates :has_redeemable_jamtrack, :inclusion => {:in => [true, false]}
|
||||
validates :subscribe_email, :inclusion => {:in => [nil, true, false]}
|
||||
validates :musician, :inclusion => {:in => [true, false]}
|
||||
validates :show_whats_next, :inclusion => {:in => [nil, true, false]}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ module JamRuby
|
|||
def initialize()
|
||||
end
|
||||
|
||||
def create_account(current_user, billing_info=nil)
|
||||
def create_account(current_user, billing_info)
|
||||
options = account_hash(current_user, billing_info)
|
||||
account = nil
|
||||
begin
|
||||
|
|
@ -37,7 +37,7 @@ module JamRuby
|
|||
end
|
||||
|
||||
def get_account(current_user)
|
||||
(current_user && current_user.recurly_code) ? Recurly::Account.find(current_user.recurly_code) : nil
|
||||
current_user && current_user.recurly_code ? Recurly::Account.find(current_user.recurly_code) : nil
|
||||
end
|
||||
|
||||
def update_account(current_user, billing_info=nil)
|
||||
|
|
@ -53,12 +53,12 @@ module JamRuby
|
|||
account
|
||||
end
|
||||
|
||||
def update_billing_info(current_user, billing_info=nil)
|
||||
def update_billing_info(current_user, billing_info)
|
||||
account = get_account(current_user)
|
||||
if (account.present?)
|
||||
begin
|
||||
account.billing_info=billing_info
|
||||
account.billing_info.save
|
||||
account.billing_info = billing_info
|
||||
account.billing_info.save
|
||||
rescue Recurly::Error, NoMethodError => x
|
||||
raise RecurlyClientError, x.to_s
|
||||
end
|
||||
|
|
@ -145,7 +145,7 @@ module JamRuby
|
|||
raise RecurlyClientError.new(plan.errors) if plan.errors.any?
|
||||
end
|
||||
|
||||
def place_order(current_user, jam_track)
|
||||
def place_order(current_user, jam_track, shopping_cart)
|
||||
jam_track_right = nil
|
||||
account = get_account(current_user)
|
||||
if (account.present?)
|
||||
|
|
@ -163,10 +163,17 @@ module JamRuby
|
|||
# this means we already have a subscription, so don't try to create a new one for the same plan (Recurly would fail this anyway)
|
||||
unless recurly_subscription_uuid
|
||||
|
||||
subscription = Recurly::Subscription.create(:account=>account, :plan_code=>jam_track.plan_code)
|
||||
# if the shopping cart was specified, see if the item should be free
|
||||
free = shopping_cart.nil? ? false : shopping_cart.free?
|
||||
# and if it's free, squish the charge to 0.
|
||||
unit_amount_in_cents = free ? 0 : nil
|
||||
subscription = Recurly::Subscription.create(:account=>account, :plan_code=>jam_track.plan_code, unit_amount_in_cents: unit_amount_in_cents)
|
||||
|
||||
raise RecurlyClientError.new(subscription.errors) if subscription.errors.any?
|
||||
|
||||
# delete from shopping cart the subscription
|
||||
shopping_cart.destroy if shopping_cart
|
||||
|
||||
# Reload and make sure it went through:
|
||||
account = get_account(current_user)
|
||||
|
||||
|
|
@ -180,7 +187,7 @@ module JamRuby
|
|||
|
||||
raise RecurlyClientError, "Plan code '#{paid_subscription.plan_code}' doesn't match jam track: '#{jam_track.plan_code}'" unless recurly_subscription_uuid
|
||||
|
||||
jam_track_right=JamRuby::JamTrackRight.find_or_create_by_user_id_and_jam_track_id(current_user.id, jam_track.id)
|
||||
jam_track_right = JamRuby::JamTrackRight.find_or_create_by_user_id_and_jam_track_id(current_user.id, jam_track.id)
|
||||
if jam_track_right.recurly_subscription_uuid != recurly_subscription_uuid
|
||||
jam_track_right.recurly_subscription_uuid = recurly_subscription_uuid
|
||||
jam_track_right.save
|
||||
|
|
@ -198,7 +205,7 @@ module JamRuby
|
|||
jam_track_right
|
||||
end
|
||||
|
||||
def find_or_create_account(current_user, billing_info=nil)
|
||||
def find_or_create_account(current_user, billing_info)
|
||||
account = get_account(current_user)
|
||||
|
||||
if(account.nil?)
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ FactoryGirl.define do
|
|||
musician true
|
||||
terms_of_service true
|
||||
last_jam_audio_latency 5
|
||||
resue_card true
|
||||
reuse_card true
|
||||
|
||||
#u.association :musician_instrument, factory: :musician_instrument, user: u
|
||||
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ describe RecurlyClient do
|
|||
|
||||
it "can place order" do
|
||||
@client.find_or_create_account(@user, @billing_info)
|
||||
expect{@client.place_order(@user, @jamtrack)}.not_to raise_error()
|
||||
expect{@client.place_order(@user, @jamtrack, nil)}.not_to raise_error()
|
||||
subs = @client.get_account(@user).subscriptions
|
||||
subs.should_not be_nil
|
||||
subs.should have(1).items
|
||||
|
|
@ -102,7 +102,7 @@ describe RecurlyClient do
|
|||
@client.find_or_create_account(@user, @billing_info)
|
||||
|
||||
# Place order:
|
||||
expect{@client.place_order(@user, @jamtrack)}.not_to raise_error()
|
||||
expect{@client.place_order(@user, @jamtrack, nil)}.not_to raise_error()
|
||||
active_subs=@client.get_account(@user).subscriptions.find_all{|t|t.state=='active'}
|
||||
@jamtrack.reload
|
||||
@jamtrack.jam_track_rights.should have(1).items
|
||||
|
|
@ -118,10 +118,10 @@ describe RecurlyClient do
|
|||
|
||||
it "detects error on double order" do
|
||||
@client.find_or_create_account(@user, @billing_info)
|
||||
jam_track_right = @client.place_order(@user, @jamtrack)
|
||||
jam_track_right = @client.place_order(@user, @jamtrack, nil)
|
||||
jam_track_right.recurly_subscription_uuid.should_not be_nil
|
||||
|
||||
jam_track_right2 = @client.place_order(@user, @jamtrack)
|
||||
jam_track_right2 = @client.place_order(@user, @jamtrack, nil)
|
||||
jam_track_right.should eq(jam_track_right2)
|
||||
jam_track_right.recurly_subscription_uuid.should eq(jam_track_right.recurly_subscription_uuid)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -166,6 +166,10 @@ def app_config
|
|||
20 # 20 seconds
|
||||
end
|
||||
|
||||
def one_free_jamtrack_per_user
|
||||
true
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,368 @@
|
|||
(function (context, $) {
|
||||
|
||||
"use strict";
|
||||
context.JK = context.JK || {};
|
||||
context.JK.CheckoutOrderScreen = function (app) {
|
||||
|
||||
var EVENTS = context.JK.EVENTS;
|
||||
var logger = context.JK.logger;
|
||||
var rest = context.JK.Rest();
|
||||
var jamTrackUtils = context.JK.JamTrackUtils;
|
||||
|
||||
var $screen = null;
|
||||
var $navigation = null;
|
||||
var $templateOrderContent = null;
|
||||
var $templatePurchasedJamTrack = null;
|
||||
var $orderPanel = null;
|
||||
var $thanksPanel = null;
|
||||
var $jamTrackInBrowser = null;
|
||||
var $purchasedJamTrack = null;
|
||||
var $purchasedJamTrackHeader = null;
|
||||
var $purchasedJamTracks = null;
|
||||
var $orderContent = null;
|
||||
var userDetail = null;
|
||||
var step = null;
|
||||
var downloadJamTracks = [];
|
||||
var purchasedJamTracks = null;
|
||||
var purchasedJamTrackIterator = 0;
|
||||
var $backBtn = null;
|
||||
var $paymentPrompt = null;
|
||||
var $emptyCartPrompt = null;
|
||||
|
||||
|
||||
function beforeShow() {
|
||||
beforeShowOrder();
|
||||
}
|
||||
|
||||
|
||||
function afterShow(data) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
function beforeHide() {
|
||||
if(downloadJamTracks) {
|
||||
context._.each(downloadJamTracks, function(downloadJamTrack) {
|
||||
downloadJamTrack.destroy();
|
||||
downloadJamTrack.root.remove();
|
||||
})
|
||||
|
||||
downloadJamTracks = [];
|
||||
}
|
||||
purchasedJamTracks = null;
|
||||
purchasedJamTrackIterator = 0;
|
||||
}
|
||||
|
||||
function beforeShowOrder() {
|
||||
$paymentPrompt.addClass('hidden')
|
||||
$emptyCartPrompt.addClass('hidden')
|
||||
$orderPanel.removeClass("hidden")
|
||||
$thanksPanel.addClass("hidden")
|
||||
$orderContent.find(".place-order").addClass('disabled').off('click', placeOrder)
|
||||
step = 3;
|
||||
renderNavigation();
|
||||
populateOrderPage();
|
||||
}
|
||||
|
||||
|
||||
function populateOrderPage() {
|
||||
clearOrderPage();
|
||||
|
||||
rest.getShoppingCarts()
|
||||
.done(function(carts) {
|
||||
rest.getBillingInfo()
|
||||
.done(function(billingInfo) {
|
||||
renderOrderPage(carts, billingInfo)
|
||||
})
|
||||
.fail(function(jqXHR) {
|
||||
if(jqXHR.status == 404) {
|
||||
// no account for this user
|
||||
app.notify({ title: "No account information",
|
||||
text: "Please restart the checkout process." },
|
||||
null,
|
||||
true);
|
||||
}
|
||||
})
|
||||
})
|
||||
.fail(app.ajaxError);
|
||||
}
|
||||
|
||||
|
||||
function renderOrderPage(carts, recurlyAccountInfo) {
|
||||
logger.debug("rendering order page")
|
||||
var data = {}
|
||||
|
||||
var sub_total = 0.0
|
||||
var taxes = 0.0
|
||||
$.each(carts, function(index, cart) {
|
||||
sub_total += parseFloat(cart.product_info.total_price)
|
||||
});
|
||||
//data.grand_total = (sub_total + taxes).toFixed(2)
|
||||
data.sub_total = sub_total.toFixed(2)
|
||||
//data.taxes = taxes.toFixed(2)
|
||||
data.carts = carts
|
||||
data.billing_info = recurlyAccountInfo.billing_info
|
||||
data.shipping_info = recurlyAccountInfo.address
|
||||
|
||||
data.shipping_as_billing = true; //jamTrackUtils.compareAddress(data.billing_info, data.shipping_info);
|
||||
|
||||
var orderContentHtml = $(
|
||||
context._.template(
|
||||
$templateOrderContent.html(),
|
||||
data,
|
||||
{variable: 'data'}
|
||||
)
|
||||
)
|
||||
|
||||
$orderContent.append(orderContentHtml)
|
||||
$orderPanel.find(".change-payment-info").on('click', moveToPaymentInfo)
|
||||
|
||||
var $placeOrder = $screen.find(".place-order")
|
||||
if(carts.length == 0) {
|
||||
$paymentPrompt.addClass('hidden')
|
||||
$emptyCartPrompt.removeClass('hidden')
|
||||
$placeOrder.addClass('disabled')
|
||||
}
|
||||
else {
|
||||
logger.debug("cart has " + carts.length + " items in it")
|
||||
$paymentPrompt.removeClass('hidden')
|
||||
$emptyCartPrompt.addClass('hidden')
|
||||
$placeOrder.removeClass('disabled').on('click', placeOrder)
|
||||
|
||||
var planPricing = {}
|
||||
|
||||
context._.each(carts, function(cart) {
|
||||
var priceElement = $screen.find('.order-right-page .plan[data-plan-code="' + cart.product_info.plan_code +'"]')
|
||||
|
||||
if(priceElement.length == 0) {
|
||||
logger.error("unable to find price element for " + cart.product_info.plan_code, cart);
|
||||
app.notify({title: "Error Encountered", text: "Unable to find plan info for " + cart.product_info.plan_code})
|
||||
return false;
|
||||
}
|
||||
|
||||
logger.debug("creating recurly pricing element for plan: " + cart.product_info.plan_code)
|
||||
var pricing = context.recurly.Pricing();
|
||||
pricing.plan_code = cart.product_info.plan_code;
|
||||
pricing.resolved = false;
|
||||
pricing.effective_quantity = cart.product_info.quantity - cart.product_info.marked_for_redeem
|
||||
planPricing[pricing.plan_code] = pricing;
|
||||
|
||||
// this is called when the plan is resolved against Recurly. It will have tax info, which is the only way we can get it.
|
||||
pricing.on('change', function(price) {
|
||||
|
||||
var resolvedPrice = planPricing[this.plan_code];
|
||||
if(!resolvedPrice) {
|
||||
logger.error("unable to find price info in storage")
|
||||
app.notify({title: "Error Encountered", text: "Unable to find plan info in storage"})
|
||||
return;
|
||||
}
|
||||
else {
|
||||
logger.debug("pricing resolved for plan: " + this.plan_code)
|
||||
}
|
||||
resolvedPrice.resolved = true;
|
||||
|
||||
var allResolved = true;
|
||||
var totalTax = 0;
|
||||
var totalPrice = 0;
|
||||
|
||||
// let's see if all plans have been resolved via API; and add up total price and taxes for display
|
||||
$.each(planPricing, function(plan_code, priceObject) {
|
||||
logger.debug("resolved recurly priceObject", priceObject)
|
||||
|
||||
if(!priceObject.resolved) {
|
||||
allResolved = false;
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
var unitTax = Number(priceObject.price.now.tax) * priceObject.effective_quantity;
|
||||
totalTax += unitTax;
|
||||
|
||||
var totalUnitPrice = Number(priceObject.price.now.total) * priceObject.effective_quantity;
|
||||
totalPrice += totalUnitPrice;
|
||||
}
|
||||
})
|
||||
|
||||
if(allResolved) {
|
||||
$screen.find('.order-right-page .order-items-value.taxes').text('$' + totalTax.toFixed(2))
|
||||
$screen.find('.order-right-page .order-items-value.order-total').text('$' + totalPrice.toFixed(2))
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.debug("still waiting on more plans to resolve")
|
||||
}
|
||||
})
|
||||
pricing.attach(priceElement.eq(0))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function moveToPaymentInfo() {
|
||||
context.location = '/client#/checkoutPayment';
|
||||
return false;
|
||||
}
|
||||
|
||||
function placeOrder(e) {
|
||||
e.preventDefault();
|
||||
$screen.find(".place-order").off('click').addClass('disabled')
|
||||
rest.placeOrder()
|
||||
.done(moveToThanks)
|
||||
.fail(orderErrorHandling);
|
||||
}
|
||||
|
||||
|
||||
function orderErrorHandling(xhr, ajaxOptions, thrownError) {
|
||||
if (xhr && xhr.responseJSON) {
|
||||
var message = "Error submitting payment: "
|
||||
$.each(xhr.responseJSON.errors, function (key, error) {
|
||||
message += key + ": " + error
|
||||
})
|
||||
$("#order_error").text(message).removeClass("hidden")
|
||||
}
|
||||
else {
|
||||
$("#order_error").text(xhr.responseText).removeClass("hidden")
|
||||
}
|
||||
$orderContent.find(".place-order").on('click', placeOrder)
|
||||
}
|
||||
|
||||
function moveToThanks(purchaseResponse) {
|
||||
$("#order_error").addClass("hidden")
|
||||
$orderPanel.addClass("hidden")
|
||||
$thanksPanel.removeClass("hidden")
|
||||
jamTrackUtils.checkShoppingCart()
|
||||
//beforeShowOrder()
|
||||
handleJamTracksPurchased(purchaseResponse.jam_tracks)
|
||||
}
|
||||
|
||||
function handleJamTracksPurchased(jamTracks) {
|
||||
// were any JamTracks purchased?
|
||||
var jamTracksPurchased = jamTracks && jamTracks.length > 0;
|
||||
if(jamTracksPurchased) {
|
||||
if(gon.isNativeClient) {
|
||||
startDownloadJamTracks(jamTracks)
|
||||
}
|
||||
else {
|
||||
$jamTrackInBrowser.removeClass('hidden');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function startDownloadJamTracks(jamTracks) {
|
||||
// there can be multiple purchased JamTracks, so we cycle through them
|
||||
|
||||
purchasedJamTracks = jamTracks;
|
||||
|
||||
// populate list of jamtracks purchased, that we will iterate through graphically
|
||||
context._.each(jamTracks, function(jamTrack) {
|
||||
var downloadJamTrack = new context.JK.DownloadJamTrack(app, jamTrack, 'small');
|
||||
var $purchasedJamTrack = $(context._.template(
|
||||
$templatePurchasedJamTrack.html(),
|
||||
jamTrack,
|
||||
{variable: 'data'}
|
||||
));
|
||||
|
||||
$purchasedJamTracks.append($purchasedJamTrack)
|
||||
|
||||
// show it on the page
|
||||
$purchasedJamTrack.append(downloadJamTrack.root)
|
||||
|
||||
downloadJamTracks.push(downloadJamTrack)
|
||||
})
|
||||
|
||||
iteratePurchasedJamTracks();
|
||||
}
|
||||
|
||||
function iteratePurchasedJamTracks() {
|
||||
if(purchasedJamTrackIterator < purchasedJamTracks.length ) {
|
||||
var downloadJamTrack = downloadJamTracks[purchasedJamTrackIterator++];
|
||||
|
||||
// make sure the 'purchasing JamTrack' section can be seen
|
||||
$purchasedJamTrack.removeClass('hidden');
|
||||
|
||||
// the widget indicates when it gets to any transition; we can hide it once it reaches completion
|
||||
$(downloadJamTrack).on(EVENTS.JAMTRACK_DOWNLOADER_STATE_CHANGED, function(e, data) {
|
||||
|
||||
if(data.state == downloadJamTrack.states.synchronized) {
|
||||
logger.debug("jamtrack " + downloadJamTrack.jamTrack.name + " synchronized;")
|
||||
//downloadJamTrack.root.remove();
|
||||
downloadJamTrack.destroy();
|
||||
|
||||
// go to the next JamTrack
|
||||
iteratePurchasedJamTracks()
|
||||
}
|
||||
})
|
||||
|
||||
logger.debug("jamtrack " + downloadJamTrack.jamTrack.name + " downloader initializing")
|
||||
|
||||
// kick off the download JamTrack process
|
||||
downloadJamTrack.init()
|
||||
|
||||
// XXX style-test code
|
||||
// downloadJamTrack.transitionError("package-error", "The server failed to create your package.")
|
||||
|
||||
}
|
||||
else {
|
||||
logger.debug("done iterating over purchased JamTracks")
|
||||
$purchasedJamTrackHeader.text('All purchased JamTracks have been downloaded successfully! You can now play them in a session.')
|
||||
}
|
||||
}
|
||||
|
||||
function clearOrderPage() {
|
||||
$orderContent.empty();
|
||||
}
|
||||
|
||||
function renderNavigation() {
|
||||
$navigation.html("");
|
||||
var navigationHtml = $(
|
||||
context._.template(
|
||||
$('#template-checkout-navigation').html(),
|
||||
{current: step},
|
||||
{variable: 'data'}
|
||||
)
|
||||
);
|
||||
|
||||
$navigation.append(navigationHtml);
|
||||
}
|
||||
|
||||
function events() {
|
||||
$backBtn.on('click', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
context.location = '/client#/checkoutPayment'
|
||||
})
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
var screenBindings = {
|
||||
'beforeShow': beforeShow,
|
||||
'afterShow': afterShow,
|
||||
'beforeHide': beforeHide
|
||||
};
|
||||
app.bindScreen('checkoutOrder', screenBindings);
|
||||
|
||||
$screen = $("#checkoutOrderScreen");
|
||||
$navigation = $screen.find(".checkout-navigation-bar");
|
||||
$templateOrderContent = $("#template-order-content");
|
||||
$templatePurchasedJamTrack = $('#template-purchased-jam-track');
|
||||
$orderPanel = $screen.find(".order-panel");
|
||||
$thanksPanel = $screen.find(".thanks-panel");
|
||||
$jamTrackInBrowser = $screen.find(".thanks-detail.jam-tracks-in-browser");
|
||||
$purchasedJamTrack = $thanksPanel.find(".thanks-detail.purchased-jam-track");
|
||||
$purchasedJamTrackHeader = $purchasedJamTrack.find(".purchased-jam-track-header");
|
||||
$purchasedJamTracks = $purchasedJamTrack.find(".purchased-list")
|
||||
$backBtn = $screen.find('.back');
|
||||
$paymentPrompt = $screen.find('.payment-prompt');
|
||||
$emptyCartPrompt = $screen.find('.empty-cart-prompt');
|
||||
$orderContent = $orderPanel.find(".order-content");
|
||||
|
||||
if ($screen.length == 0) throw "$screen must be specified";
|
||||
if ($navigation.length == 0) throw "$navigation must be specified";
|
||||
|
||||
events();
|
||||
}
|
||||
|
||||
this.initialize = initialize;
|
||||
|
||||
return this;
|
||||
}
|
||||
})
|
||||
(window, jQuery);
|
||||
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
var EVENTS = context.JK.EVENTS;
|
||||
var logger = context.JK.logger;
|
||||
var jamTrackUtils = context.JK.JamTrackUtils;
|
||||
|
||||
var $screen = null;
|
||||
var $navigation = null;
|
||||
|
|
@ -21,8 +22,17 @@
|
|||
var billing_info = null;
|
||||
var shipping_info = null;
|
||||
var shipping_as_billing = null;
|
||||
var $reuseExistingCard = null;
|
||||
var $reuseExistingCardChk = null;
|
||||
var $existingCardEndsWith = null;
|
||||
var $newCardInfo = null;
|
||||
var selectCountry = null;
|
||||
var selectCountryLoaded = false;
|
||||
var $freeJamTrackPrompt = null;
|
||||
var $noFreeJamTrackPrompt = null;
|
||||
|
||||
function afterShow() {
|
||||
|
||||
function beforeShow() {
|
||||
beforeShowPaymentInfo();
|
||||
}
|
||||
|
||||
|
|
@ -30,39 +40,76 @@
|
|||
step = 2;
|
||||
renderNavigation();
|
||||
renderAccountInfo();
|
||||
|
||||
}
|
||||
|
||||
|
||||
function renderAccountInfo() {
|
||||
var user = rest.getUserDetail()
|
||||
$reuseExistingCard.addClass('hidden');
|
||||
$newCardInfo.removeClass('hidden');
|
||||
$freeJamTrackPrompt.addClass('hidden');
|
||||
$noFreeJamTrackPrompt.addClass('hidden');
|
||||
|
||||
var selectCountryReady = selectCountry.ready();
|
||||
if(!selectCountryReady) {
|
||||
// one time init of country dropdown
|
||||
selectCountryReady = selectCountry.load('US', null, null);
|
||||
}
|
||||
|
||||
selectCountryReady.done(function() {
|
||||
var user = rest.getUserDetail()
|
||||
if(user) {
|
||||
user.done(populateAccountInfo).error(app.ajaxError);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function populateAccountInfo(user) {
|
||||
userDetail = user;
|
||||
|
||||
$reuseExistingCardChk.iCheck(userDetail.reuse_card ? 'check' : 'uncheck').attr('checked', userDetail.reuse_card)
|
||||
|
||||
// show appropriate prompt text based on whether user has a free jamtrack
|
||||
if(user.free_jamtrack) {
|
||||
$freeJamTrackPrompt.removeClass('hidden')
|
||||
}
|
||||
else {
|
||||
$noFreeJamTrackPrompt.removeClass('hidden')
|
||||
}
|
||||
|
||||
if (userDetail.has_recurly_account) {
|
||||
|
||||
rest.getBillingInfo()
|
||||
.done(function(response) {
|
||||
$billingInfo.find("#billing-first-name").val(response.first_name);
|
||||
$billingInfo.find("#billing-last-name").val(response.last_name);
|
||||
$billingInfo.find("#billing-address1").val(response.address1);
|
||||
$billingInfo.find("#billing-address2").val(response.address2);
|
||||
$billingInfo.find("#billing-city").val(response.city);
|
||||
$billingInfo.find("#billing-state").val(response.state);
|
||||
$billingInfo.find("#billing-zip").val(response.zip);
|
||||
$billingInfo.find("#billing-country").val(response.country);
|
||||
|
||||
$shippingAddress.find("#shipping-first-name").val(response.first_name);
|
||||
$shippingAddress.find("#shipping-last-name").val(response.last_name);
|
||||
$shippingAddress.find("#shipping-address1").val(response.address1);
|
||||
$shippingAddress.find("#shipping-address2").val(response.address2);
|
||||
$shippingAddress.find("#shipping-city").val(response.city);
|
||||
$shippingAddress.find("#shipping-state").val(response.state);
|
||||
$shippingAddress.find("#shipping-zip").val(response.zip);
|
||||
$shippingAddress.find("#shipping-country").val(response.country);
|
||||
if(userDetail.reuse_card) {
|
||||
$reuseExistingCard.removeClass('hidden');
|
||||
toggleReuseExistingCard.call($reuseExistingCardChk)
|
||||
$existingCardEndsWith.text(response.billing_info.last_four);
|
||||
}
|
||||
|
||||
var isSameAsShipping = true // jamTrackUtils.compareAddress(response.billing_info, response.address);
|
||||
|
||||
$shippingAsBilling.iCheck(isSameAsShipping ? 'check' : 'uncheck').attr('checked', isSameAsShipping)
|
||||
|
||||
$billingInfo.find("#billing-first-name").val(response.billing_info.first_name);
|
||||
$billingInfo.find("#billing-last-name").val(response.billing_info.last_name);
|
||||
$billingInfo.find("#billing-address1").val(response.billing_info.address1);
|
||||
$billingInfo.find("#billing-address2").val(response.billing_info.address2);
|
||||
$billingInfo.find("#billing-city").val(response.billing_info.city);
|
||||
$billingInfo.find("#billing-state").val(response.billing_info.state);
|
||||
$billingInfo.find("#billing-zip").val(response.billing_info.zip);
|
||||
$billingInfo.find("#billing-country").val(response.billing_info.country);
|
||||
|
||||
//$shippingAddress.find("#shipping-first-name").val(response.billing_info.first_name);
|
||||
//$shippingAddress.find("#shipping-last-name").val(response.billing_info.last_name);
|
||||
//$shippingAddress.find("#shipping-address1").val(response.address.address1);
|
||||
//$shippingAddress.find("#shipping-address2").val(response.address.address2);
|
||||
//$shippingAddress.find("#shipping-city").val(response.address.city);
|
||||
//$shippingAddress.find("#shipping-state").val(response.address.state);
|
||||
//$shippingAddress.find("#shipping-zip").val(response.address.zip);
|
||||
//$shippingAddress.find("#shipping-country").val(response.address.country);
|
||||
|
||||
})
|
||||
.error(app.ajaxError);
|
||||
}
|
||||
|
|
@ -81,7 +128,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
function afterShow(data) {
|
||||
function beforeShow(data) {
|
||||
// XXX : style-test code
|
||||
// moveToThanks({jam_tracks: [{id: 14, jam_track_right_id: 11, name: 'Back in Black'}, {id: 15, jam_track_right_id: 11, name: 'In Bloom'}, {id: 16, jam_track_right_id: 11, name: 'Love Bird Supreme'}]});
|
||||
}
|
||||
|
|
@ -96,8 +143,14 @@
|
|||
|
||||
// TODO: Refactor: this function is long and fraught with many return points.
|
||||
function next(e) {
|
||||
$paymentInfoPanel.find('.error-text').remove();
|
||||
$paymentInfoPanel.find('.error').removeClass('error');
|
||||
e.preventDefault();
|
||||
$("#order_error").addClass("hidden")
|
||||
$("#payment_error").addClass("hidden")
|
||||
|
||||
var reuse_card_this_time = $reuseExistingCardChk.is(':checked');
|
||||
var reuse_card_next_time = $paymentMethod.find('#save-card').is(':checked');
|
||||
|
||||
|
||||
// validation
|
||||
var billing_first_name = $billingInfo.find("#billing-first-name").val();
|
||||
|
|
@ -114,6 +167,7 @@
|
|||
$billingInfo.find('#divBillingFirstName').addClass("error");
|
||||
$billingInfo.find('#billing-first-name').after("<ul class='error-text'><li>First Name is required</li></ul>");
|
||||
|
||||
logger.info("no billing first name");
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
|
|
@ -125,6 +179,7 @@
|
|||
$billingInfo.find('#divBillingLastName').addClass("error");
|
||||
$billingInfo.find('#billing-last-name').after("<ul class='error-text'><li>Last Name is required</li></ul>");
|
||||
|
||||
logger.info("no billing last name");
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
|
|
@ -136,6 +191,7 @@
|
|||
$billingInfo.find('#divBillingAddress1').addClass("error");
|
||||
$billingInfo.find('#billing-address1').after("<ul class='error-text'><li>Address is required</li></ul>");
|
||||
|
||||
logger.info("no billing address line 1");
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
|
|
@ -147,6 +203,7 @@
|
|||
$billingInfo.find('#divBillingZip').addClass("error");
|
||||
$billingInfo.find('#billing-zip').after("<ul class='error-text'><li>Zip code is required</li></ul>");
|
||||
|
||||
logger.info("no billing address line 2");
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
|
|
@ -158,6 +215,7 @@
|
|||
$billingInfo.find('#divBillingState').addClass("error");
|
||||
$billingInfo.find('#billing-zip').after("<ul class='error-text'><li>State is required</li></ul>");
|
||||
|
||||
logger.info("no billing zip");
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
|
|
@ -169,6 +227,7 @@
|
|||
$billingInfo.find('#divBillingCity').addClass("error");
|
||||
$billingInfo.find('#billing-city').after("<ul class='error-text'><li>City is required</li></ul>");
|
||||
|
||||
logger.info("no billing city");
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
|
|
@ -180,12 +239,14 @@
|
|||
$billingInfo.find('#divBillingCountry').addClass("error");
|
||||
$billingInfo.find('#billing-country').after("<ul class='error-text'><li>Country is required</li></ul>");
|
||||
|
||||
logger.info("no billing country");
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
$billingInfo.find('#divBillingCountry').removeClass("error");
|
||||
}
|
||||
|
||||
/**
|
||||
shipping_as_billing = $shippingAsBilling.is(":checked");
|
||||
var shipping_first_name, shipping_last_name, shipping_address1, shipping_address2;
|
||||
var shipping_city, shipping_state, shipping_zip, shipping_country;
|
||||
|
|
@ -205,6 +266,7 @@
|
|||
$shippingAddress.find('#divShippingFirstName').addClass("error");
|
||||
$shippingAddress.find('#shipping-first-name').after("<ul class='error-text'><li>First Name is required</li></ul>");
|
||||
|
||||
logger.info("no address first name");
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
|
|
@ -216,6 +278,7 @@
|
|||
$shippingAddress.find('#divShippingLastName').addClass("error");
|
||||
$shippingAddress.find('#shipping-last-name').after("<ul class='error-text'><li>Last Name is required</li></ul>");
|
||||
|
||||
logger.info("no last name");
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
|
|
@ -227,6 +290,7 @@
|
|||
$shippingAddress.find('#divShippingAddress1').addClass("error");
|
||||
$shippingAddress.find('#shipping-address1').after("<ul class='error-text'><li>Address is required</li></ul>");
|
||||
|
||||
logger.info("no shipping address 1");
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
|
|
@ -238,6 +302,7 @@
|
|||
$shippingAddress.find('#divShippingZip').addClass("error");
|
||||
$shippingAddress.find('#shipping-zip').after("<ul class='error-text'><li>Zip code is required</li></ul>");
|
||||
|
||||
logger.info("no shipping address 2");
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
|
|
@ -249,6 +314,7 @@
|
|||
$shippingAddress.find('#divShippingState').addClass("error");
|
||||
$shippingAddress.find('#shipping-zip').after("<ul class='error-text'><li>State is required</li></ul>");
|
||||
|
||||
logger.info("no shipping state");
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
|
|
@ -260,6 +326,7 @@
|
|||
$shippingAddress.find('#divShippingCity').addClass("error");
|
||||
$shippingAddress.find('#shipping-city').after("<ul class='error-text'><li>City is required</li></ul>");
|
||||
|
||||
logger.info("no shipping city");
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
|
|
@ -271,12 +338,14 @@
|
|||
$shippingAddress.find('#divShippingCountry').addClass("error");
|
||||
$shippingAddress.find('#shipping-country').after("<ul class='error-text'><li>Country is required</li></ul>");
|
||||
|
||||
logger.info("no shipping country");
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
$shippingAddress.find('#divShippingCountry').removeClass("error");
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
var card_name = $paymentMethod.find("#card-name").val();
|
||||
var card_number = $paymentMethod.find("#card-number").val();
|
||||
|
|
@ -284,6 +353,7 @@
|
|||
var card_month = $paymentMethod.find("#card_expire-date_2i").val();
|
||||
var card_verify = $paymentMethod.find("#card-verify").val();
|
||||
|
||||
/**
|
||||
if (!card_name) {
|
||||
$paymentMethod.find('#divCardName .error-text').remove();
|
||||
$paymentMethod.find('#divCardName').addClass("error");
|
||||
|
|
@ -291,46 +361,54 @@
|
|||
return false;
|
||||
} else {
|
||||
$paymentMethod.find('#divCardName').removeClass("error");
|
||||
}*/
|
||||
|
||||
// don't valid card form fields when reuse card selected
|
||||
if(!reuse_card_this_time) {
|
||||
if (!card_number) {
|
||||
$paymentMethod.find('#divCardNumber .error-text').remove();
|
||||
$paymentMethod.find('#divCardNumber').addClass("error");
|
||||
$paymentMethod.find('#card-number').after("<ul class='error-text'><li>Card Number is required</li></ul>");
|
||||
logger.info("no card number");
|
||||
return false;
|
||||
} else if (!$.payment.validateCardNumber(card_number)) {
|
||||
$paymentMethod.find('#divCardNumber .error-text').remove();
|
||||
$paymentMethod.find('#divCardNumber').addClass("error");
|
||||
$paymentMethod.find('#card-number').after("<ul class='error-text'><li>Card Number is not valid</li></ul>");
|
||||
logger.info("invalid card number");
|
||||
return false;
|
||||
} else {
|
||||
$paymentMethod.find('#divCardNumber').removeClass("error");
|
||||
}
|
||||
|
||||
if (!$.payment.validateCardExpiry(card_month, card_year)) {
|
||||
$paymentMethod.find('#divCardExpiry .error-text').remove();
|
||||
$paymentMethod.find('#divCardExpiry').addClass("error");
|
||||
$paymentMethod.find('#card-expiry').after("<ul class='error-text'><li>Card Number is not valid</li></ul>");
|
||||
logger.info("invalid card expiry");
|
||||
return false;
|
||||
} else {
|
||||
$paymentMethod.find('#divCardExpiry').removeClass("error");
|
||||
}
|
||||
|
||||
if (!card_verify) {
|
||||
$paymentMethod.find('#divCardVerify .error-text').remove();
|
||||
$paymentMethod.find('#divCardVerify').addClass("error");
|
||||
$paymentMethod.find('#card-verify').after("<ul class='error-text'><li>Card Verification Value is required</li></ul>");
|
||||
|
||||
logger.info("no card verify");
|
||||
return false;
|
||||
} else if (!$.payment.validateCardCVC(card_verify)) {
|
||||
$paymentMethod.find('#divCardVerify .error-text').remove();
|
||||
$paymentMethod.find('#divCardVerify').addClass("error");
|
||||
$paymentMethod.find('#card-verify').after("<ul class='error-text'><li>Card Verification Value is not valid.</li></ul>");
|
||||
|
||||
logger.info("bad card CVC");
|
||||
return false;
|
||||
} else {
|
||||
$paymentMethod.find('#divCardVerify').removeClass("error");
|
||||
}
|
||||
}
|
||||
|
||||
if (!card_number) {
|
||||
$paymentMethod.find('#divCardNumber .error-text').remove();
|
||||
$paymentMethod.find('#divCardNumber').addClass("error");
|
||||
$paymentMethod.find('#card-number').after("<ul class='error-text'><li>Card Number is required</li></ul>");
|
||||
return false;
|
||||
} else if (!$.payment.validateCardNumber(card_number)) {
|
||||
$paymentMethod.find('#divCardNumber .error-text').remove();
|
||||
$paymentMethod.find('#divCardNumber').addClass("error");
|
||||
$paymentMethod.find('#card-number').after("<ul class='error-text'><li>Card Number is not valid</li></ul>");
|
||||
return false;
|
||||
} else {
|
||||
$paymentMethod.find('#divCardNumber').removeClass("error");
|
||||
}
|
||||
|
||||
if (!$.payment.validateCardExpiry(card_month, card_year)) {
|
||||
$paymentMethod.find('#divCardExpiry .error-text').remove();
|
||||
$paymentMethod.find('#divCardExpiry').addClass("error");
|
||||
$paymentMethod.find('#card-expiry').after("<ul class='error-text'><li>Card Number is not valid</li></ul>");
|
||||
} else {
|
||||
$paymentMethod.find('#divCardExpiry').removeClass("error");
|
||||
}
|
||||
|
||||
if (!card_verify) {
|
||||
$paymentMethod.find('#divCardVerify .error-text').remove();
|
||||
$paymentMethod.find('#divCardVerify').addClass("error");
|
||||
$paymentMethod.find('#card-verify').after("<ul class='error-text'><li>Card Verification Value is required</li></ul>");
|
||||
|
||||
return false;
|
||||
} else if(!$.payment.validateCardCVC(card_verify)) {
|
||||
$paymentMethod.find('#divCardVerify .error-text').remove();
|
||||
$paymentMethod.find('#divCardVerify').addClass("error");
|
||||
$paymentMethod.find('#card-verify').after("<ul class='error-text'><li>Card Verification Value is not valid.</li></ul>");
|
||||
|
||||
return false;
|
||||
} else {
|
||||
$paymentMethod.find('#divCardVerify').removeClass("error");
|
||||
}
|
||||
|
||||
billing_info = {};
|
||||
shipping_info = {};
|
||||
billing_info.first_name = billing_first_name;
|
||||
|
|
@ -346,6 +424,7 @@
|
|||
billing_info.year = card_year;
|
||||
billing_info.verification_value = card_verify;
|
||||
|
||||
/**
|
||||
if (shipping_as_billing) {
|
||||
shipping_info = $.extend({},billing_info);
|
||||
delete shipping_info.number;
|
||||
|
|
@ -361,69 +440,83 @@
|
|||
shipping_info.state = shipping_state;
|
||||
shipping_info.country = shipping_country;
|
||||
shipping_info.zip = shipping_zip;
|
||||
}
|
||||
|
||||
$paymentInfoPanel.find("#payment-info-next").addClass("disabled");
|
||||
$paymentInfoPanel.find("#payment-info-next").off("click");
|
||||
|
||||
var reuse_card = $paymentMethod.find('#save-card').is(':checked');
|
||||
|
||||
}*/
|
||||
|
||||
var email = null;
|
||||
var password = null;
|
||||
var terms = false;
|
||||
var isLoggedIn = context.JK.currentUserId;
|
||||
if(!isLoggedIn) {
|
||||
email = $accountSignup.find('input[name="email"]').val()
|
||||
password = $accountSignup.find('input[name="password"]').val()
|
||||
terms = $accountSignup.find('input[name="terms-of-service"]').is(':checked');
|
||||
}
|
||||
|
||||
rest.createRecurlyAccount({billing_info: billing_info, terms_of_service: true, email: email, password: password, reuse_card: reuse_card})
|
||||
$screen.find("#payment-info-next").addClass("disabled");
|
||||
$screen.find("#payment-info-next").off("click");
|
||||
rest.createRecurlyAccount({billing_info: billing_info, terms_of_service: terms, email: email, password: password, reuse_card_this_time: reuse_card_this_time, reuse_card_next_time: reuse_card_next_time})
|
||||
.done(function() {
|
||||
$paymentInfoPanel.find("#payment-info-next").removeClass("disabled");
|
||||
$paymentInfoPanel.find("#payment-info-next").on("click", next);
|
||||
$screen.find("#payment-info-next").on("click", next);
|
||||
|
||||
if(isLoggedIn) {
|
||||
context.location = '/client#checkout_order'
|
||||
context.location = '/client#/checkoutOrder'
|
||||
}
|
||||
else {
|
||||
// this means the account was created; we need to reload the page for this to take effect
|
||||
context.location = '/client#checkout_order'
|
||||
context.JK.currentUserId = 'something' // this is to trick layout.js from getting involved and redirecting to home screen
|
||||
context.location = '/client#/checkoutOrder'
|
||||
context.location.reload()
|
||||
}
|
||||
})
|
||||
.fail(errorHandling);
|
||||
.fail(errorHandling)
|
||||
.always(function(){
|
||||
$screen.find("#payment-info-next").removeClass("disabled");
|
||||
})
|
||||
}
|
||||
|
||||
function errorHandling(xhr, ajaxOptions, thrownError) {
|
||||
$.each(xhr.responseJSON.errors, function(key, error) {
|
||||
if (key == 'number') {
|
||||
$paymentMethod.find('#divCardNumber .error-text').remove();
|
||||
$paymentMethod.find('#divCardNumber').addClass("error");
|
||||
$paymentMethod.find('#card-number').after("<ul class='error-text'><li>" + error + "</li></ul>");
|
||||
}
|
||||
else if (key == 'verification_value') {
|
||||
$paymentMethod.find('#divCardVerify .error-text').remove();
|
||||
$paymentMethod.find('#divCardVerify').addClass("error");
|
||||
$paymentMethod.find('#card-verify').after("<ul class='error-text'><li>" + error + "</li></ul>");
|
||||
}
|
||||
else if(key == 'email') {
|
||||
var $email = $accountSignup.find('input[name="email"]')
|
||||
var $field = $email.closest('.field')
|
||||
$field.find('.error-text').remove()
|
||||
$field.addClass("error");
|
||||
$field.append("<ul class='error-text'><li>" + error + "</li></ul>");
|
||||
}
|
||||
else if(key == 'password') {
|
||||
var $email = $accountSignup.find('input[name="password"]')
|
||||
var $field = $email.closest('.field')
|
||||
$field.find('.error-text').remove()
|
||||
$field.addClass("error");
|
||||
$field.append("<ul class='error-text'><li>" + error + "</li></ul>");
|
||||
}
|
||||
});
|
||||
logger.debug("error handling", xhr.responseJSON)
|
||||
if(xhr.responseJSON && xhr.responseJSON.errors) {
|
||||
$.each(xhr.responseJSON.errors, function(key, error) {
|
||||
if (key == 'number') {
|
||||
$paymentMethod.find('#divCardNumber .error-text').remove();
|
||||
$paymentMethod.find('#divCardNumber').addClass("error");
|
||||
$paymentMethod.find('#card-number').after("<ul class='error-text'><li>" + error + "</li></ul>");
|
||||
}
|
||||
else if (key == 'verification_value') {
|
||||
$paymentMethod.find('#divCardVerify .error-text').remove();
|
||||
$paymentMethod.find('#divCardVerify').addClass("error");
|
||||
$paymentMethod.find('#card-verify').after("<ul class='error-text'><li>" + error + "</li></ul>");
|
||||
}
|
||||
else if(key == 'email') {
|
||||
var $email = $accountSignup.find('input[name="email"]')
|
||||
var $field = $email.closest('.field')
|
||||
$field.find('.error-text').remove()
|
||||
$field.addClass("error");
|
||||
$field.append("<ul class='error-text'><li>" + error + "</li></ul>");
|
||||
}
|
||||
else if(key == 'password') {
|
||||
var $password = $accountSignup.find('input[name="password"]')
|
||||
var $field = $password.closest('.field')
|
||||
$field.find('.error-text').remove()
|
||||
$field.addClass("error");
|
||||
$field.append("<ul class='error-text'><li>" + error + "</li></ul>");
|
||||
}
|
||||
else if(key == 'terms_of_service') {
|
||||
var $terms = $accountSignup.find('input[name="terms-of-service"]')
|
||||
var $field = $terms.closest('.field')
|
||||
$field.find('.error-text').remove()
|
||||
$field.addClass("error");
|
||||
$field.append("<ul class='error-text'><li>" + error + "</li></ul>");
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
$("#payment_error").text(xhr.responseText)
|
||||
}
|
||||
|
||||
$paymentInfoPanel.find("#payment-info-next").addClass("disabled");
|
||||
$paymentInfoPanel.find("#payment-info-next").on('click', next);
|
||||
|
||||
$screen.find("#payment-info-next").on('click', next);
|
||||
}
|
||||
|
||||
function beforeShowOrder() {
|
||||
|
|
@ -440,10 +533,6 @@
|
|||
.fail(app.ajaxError);
|
||||
}
|
||||
|
||||
function moveToOrder() {
|
||||
window.location = '/client#/checkout_order';
|
||||
}
|
||||
|
||||
function toggleShippingAsBilling(e) {
|
||||
e.preventDefault();
|
||||
|
||||
|
|
@ -457,9 +546,36 @@
|
|||
}
|
||||
}
|
||||
|
||||
function toggleReuseExistingCard(e) {
|
||||
if(e) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
logger.debug("toggle reuse existing card")
|
||||
|
||||
var reuse_existing = $(this).is(':checked');
|
||||
|
||||
$('#billing-first-name').prop('disabled', reuse_existing);
|
||||
$('#billing-last-name').prop('disabled', reuse_existing);
|
||||
$('#billing-address1').prop('disabled', reuse_existing);
|
||||
$('#billing-address2').prop('disabled', reuse_existing);
|
||||
$('#billing-city').prop('disabled', reuse_existing);
|
||||
$('#billing-state').prop('disabled', reuse_existing);
|
||||
$('#billing-zip').prop('disabled', reuse_existing);
|
||||
$('#billing-country').prop('disabled', reuse_existing);
|
||||
|
||||
$('#card-name').prop('disabled', reuse_existing);
|
||||
$('#card-number').prop('disabled', reuse_existing);
|
||||
$('#card_expire-date_1i').prop('disabled', reuse_existing);
|
||||
$('#card_expire-date_2i').prop('disabled', reuse_existing);
|
||||
$('#card-verify').prop('disabled', reuse_existing);
|
||||
|
||||
}
|
||||
|
||||
function events() {
|
||||
$screen.find("#payment-info-next").on('click', next);
|
||||
$shippingAsBilling.on('ifChanged', toggleShippingAsBilling);
|
||||
$reuseExistingCardChk.on('ifChanged', toggleReuseExistingCard);
|
||||
}
|
||||
|
||||
function reset() {
|
||||
|
|
@ -489,6 +605,8 @@
|
|||
// Use jquery.payment to limit characters and length:
|
||||
$paymentMethod.find("#card-number").payment('formatCardNumber');
|
||||
$paymentMethod.find("#card-verify").payment('formatCardCVC');
|
||||
|
||||
selectCountry = new context.JK.SelectLocation($('#billing-country'), null, null, app, false)
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
|
|
@ -497,7 +615,7 @@
|
|||
'afterShow': afterShow,
|
||||
'beforeHide' : beforeHide
|
||||
};
|
||||
app.bindScreen('checkout_payment', screenBindings);
|
||||
app.bindScreen('checkoutPayment', screenBindings);
|
||||
|
||||
$screen = $("#checkoutPaymentScreen");
|
||||
$paymentInfoPanel = $screen.find("#checkout-payment-info");
|
||||
|
|
@ -508,6 +626,13 @@
|
|||
$accountSignup = $paymentInfoPanel.find('.jamkazam-account-signup')
|
||||
$shippingAddress = $paymentInfoPanel.find(".shipping-address-detail");
|
||||
$shippingAsBilling = $paymentInfoPanel.find("#shipping-as-billing");
|
||||
$reuseExistingCard = $paymentInfoPanel.find('.reuse-existing-card')
|
||||
$reuseExistingCardChk = $paymentInfoPanel.find('#reuse-existing-card')
|
||||
$existingCardEndsWith = $paymentInfoPanel.find('.existing-card-ends-with')
|
||||
$newCardInfo = $paymentInfoPanel.find('.new-card-info')
|
||||
$freeJamTrackPrompt = $screen.find('.payment-prompt.free-jamtrack')
|
||||
$noFreeJamTrackPrompt = $screen.find('.payment-prompt.no-free-jamtrack')
|
||||
|
||||
|
||||
if($screen.length == 0) throw "$screen must be specified";
|
||||
if($navigation.length == 0) throw "$navigation must be specified";
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@
|
|||
}
|
||||
|
||||
function moveNext() {
|
||||
window.location = '/client#/checkout_payment';
|
||||
window.location = '/client#/checkoutPayment';
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -69,7 +69,7 @@
|
|||
|
||||
rest.login({email: email, password: password, remember_me: true})
|
||||
.done(function() {
|
||||
window.location = '/client#/checkout_payment'
|
||||
window.location = '/client#/checkoutPayment'
|
||||
window.location.reload();
|
||||
})
|
||||
.fail(function(jqXHR) {
|
||||
|
|
@ -106,7 +106,7 @@
|
|||
'beforeShow': beforeShow,
|
||||
'afterShow': afterShow
|
||||
};
|
||||
app.bindScreen('checkout_signin', screenBindings);
|
||||
app.bindScreen('checkoutSignin', screenBindings);
|
||||
|
||||
$screen = $("#checkoutSignInScreen");
|
||||
$navigation = $screen.find(".checkout-navigation-bar");
|
||||
|
|
|
|||
|
|
@ -215,13 +215,7 @@
|
|||
}
|
||||
|
||||
function initShoppingCart(app) {
|
||||
|
||||
var user = app.user()
|
||||
if(user) {
|
||||
user.done(function(userProfile) {
|
||||
context.JK.JamTrackUtils.checkShoppingCart();
|
||||
})
|
||||
}
|
||||
context.JK.JamTrackUtils.checkShoppingCart();
|
||||
}
|
||||
|
||||
})(window, jQuery);
|
||||
|
|
|
|||
|
|
@ -473,7 +473,7 @@
|
|||
processData: false,
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify(options)
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
function getUserDetail(options) {
|
||||
|
|
@ -1547,10 +1547,10 @@
|
|||
});
|
||||
}
|
||||
|
||||
function placeOrder(options) {
|
||||
function placeOrder() {
|
||||
return $.ajax({
|
||||
type: "POST",
|
||||
url: '/api/recurly/place_order?' + $.param(options),
|
||||
url: '/api/recurly/place_order',
|
||||
dataType: "json",
|
||||
contentType: 'application/json'
|
||||
});
|
||||
|
|
|
|||
|
|
@ -22,7 +22,12 @@ class JamTrackUtils
|
|||
else
|
||||
cartLink.addClass("hidden")
|
||||
|
||||
|
||||
compareAddress: (billing, shipping) =>
|
||||
billing.address1 == shipping.address1 &&
|
||||
billing.address2 == shipping.address2 &&
|
||||
billing.zip == shipping.zip &&
|
||||
billing.city == shipping.city &&
|
||||
billing.country == shipping.country;
|
||||
|
||||
|
||||
# global instance
|
||||
|
|
|
|||
|
|
@ -115,19 +115,6 @@
|
|||
purchasedJamTrackIterator = 0;
|
||||
}
|
||||
|
||||
function beforeHide() {
|
||||
if(downloadJamTracks) {
|
||||
context._.each(downloadJamTracks, function(downloadJamTrack) {
|
||||
downloadJamTrack.destroy();
|
||||
downloadJamTrack.root.remove();
|
||||
})
|
||||
|
||||
downloadJamTracks = [];
|
||||
}
|
||||
purchasedJamTracks = null;
|
||||
purchasedJamTrackIterator = 0;
|
||||
}
|
||||
|
||||
// TODO: Refactor: this function is long and fraught with many return points.
|
||||
function next(e) {
|
||||
e.preventDefault();
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
context.JK.SelectLocation = Class.extend({
|
||||
|
||||
init: function ($countries, $regions, $cities, app) {
|
||||
init: function ($countries, $regions, $cities, app, useEasyDropdown) {
|
||||
this.api = context.JK.Rest();
|
||||
this.logger = context.JK.logger;
|
||||
this.loadingCitiesData = false;
|
||||
|
|
@ -14,9 +14,12 @@
|
|||
this.loadingCountriesData = false;
|
||||
this.nilOptionStr = '<option value=""></option>';
|
||||
this.nilOptionText = 'n/a';
|
||||
this.countriesLoaded = false;
|
||||
this.$countries = $countries;
|
||||
this.$regions = $regions;
|
||||
this.$cities = $cities;
|
||||
this.$deferred = null;
|
||||
this.useEasyDropdown = useEasyDropdown === undefined ? true : useEasyDropdown;
|
||||
this.app = app;
|
||||
|
||||
$countries.on('change', function (evt) {
|
||||
|
|
@ -24,11 +27,24 @@
|
|||
this.handleCountryChanged();
|
||||
return false;
|
||||
}.bind(this));
|
||||
$regions.on('change', function (evt) {
|
||||
evt.stopPropagation();
|
||||
this.handleRegionChanged();
|
||||
return false;
|
||||
}.bind(this));
|
||||
if($regions) {
|
||||
$regions.on('change', function (evt) {
|
||||
evt.stopPropagation();
|
||||
this.handleRegionChanged();
|
||||
return false;
|
||||
}.bind(this));
|
||||
}
|
||||
},
|
||||
selectCountry: function (country) {
|
||||
if(this.useEasyDropdown) {
|
||||
this.$countries.easyDropDown('select', country, true)
|
||||
}
|
||||
else {
|
||||
this.$countries.val(country)
|
||||
}
|
||||
},
|
||||
ready: function() {
|
||||
return this.$deferred;
|
||||
},
|
||||
load: function (country, region, city) {
|
||||
|
||||
|
|
@ -42,13 +58,9 @@
|
|||
country = 'US';
|
||||
}
|
||||
|
||||
this.loadingCountriesData = true;
|
||||
this.loadingRegionsData = true;
|
||||
this.loadingCitiesData = true;
|
||||
|
||||
// make the 3 slower requests, which only matter if the user wants to affect their ISP or location
|
||||
|
||||
this.api.getCountries()
|
||||
this.loadingCountriesData = true;
|
||||
this.$deferred = this.api.getCountries()
|
||||
.done(function (countriesx) {
|
||||
this.populateCountriesx(countriesx["countriesx"], country);
|
||||
}.bind(this))
|
||||
|
|
@ -57,7 +69,9 @@
|
|||
this.loadingCountriesData = false;
|
||||
}.bind(this))
|
||||
|
||||
if (country) {
|
||||
|
||||
if (country && this.$regions) {
|
||||
this.loadingRegionsData = true;
|
||||
this.api.getRegions({ country: country })
|
||||
.done(function (regions) {
|
||||
this.populateRegions(regions["regions"], region);
|
||||
|
|
@ -67,7 +81,8 @@
|
|||
this.loadingRegionsData = false;
|
||||
}.bind(this))
|
||||
|
||||
if (region) {
|
||||
if (region && this.$cities) {
|
||||
this.loadingCitiesData = true;
|
||||
this.api.getCities({ country: country, region: region })
|
||||
.done(function (cities) {
|
||||
this.populateCities(cities["cities"], this.city)
|
||||
|
|
@ -78,9 +93,15 @@
|
|||
}.bind(this))
|
||||
}
|
||||
}
|
||||
return this.$deferred;
|
||||
},
|
||||
handleCountryChanged: function () {
|
||||
var selectedCountry = this.$countries.val()
|
||||
|
||||
if(!this.$regions) {
|
||||
return;
|
||||
}
|
||||
|
||||
var selectedRegion = this.$regions.val()
|
||||
var cityElement = this.$cities
|
||||
|
||||
|
|
@ -144,7 +165,9 @@
|
|||
else {
|
||||
cityElement.children().remove();
|
||||
cityElement.append($(this.nilOptionStr).text(this.nilOptionText));
|
||||
context.JK.dropdown(cityElement);
|
||||
if(this.useEasyDropdown) {
|
||||
context.JK.dropdown(cityElement);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -159,7 +182,7 @@
|
|||
if (!countryx.countrycode) return;
|
||||
|
||||
var option = $(this.nilOptionStr);
|
||||
option.text(countryx.countryname);
|
||||
option.text(countryx.countryname ? countryx.countryname : countryx.countrycode);
|
||||
option.attr("value", countryx.countrycode);
|
||||
|
||||
if (countryx.countrycode == this.country) {
|
||||
|
|
@ -170,6 +193,8 @@
|
|||
},
|
||||
populateCountriesx: function (countriesx) {
|
||||
|
||||
this.countriesLoaded = true;
|
||||
|
||||
// countriesx has the format [{countrycode: "US", countryname: "United States"}, ...]
|
||||
|
||||
this.foundCountry = false;
|
||||
|
|
@ -194,8 +219,9 @@
|
|||
|
||||
this.$countries.val(this.country);
|
||||
this.$countries.attr("disabled", null).easyDropDown('enable');
|
||||
|
||||
context.JK.dropdown(this.$countries);
|
||||
if(this.useEasyDropdown) {
|
||||
context.JK.dropdown(this.$countries);
|
||||
}
|
||||
},
|
||||
|
||||
writeRegion: function (index, region) {
|
||||
|
|
@ -220,7 +246,9 @@
|
|||
this.$regions.val(userRegion)
|
||||
this.$regions.attr("disabled", null).easyDropDown('enable');
|
||||
|
||||
context.JK.dropdown(this.$regions);
|
||||
if(this.useEasyDropdown) {
|
||||
context.JK.dropdown(this.$regions);
|
||||
}
|
||||
},
|
||||
|
||||
writeCity: function (index, city) {
|
||||
|
|
@ -245,7 +273,9 @@
|
|||
this.$cities.val(userCity)
|
||||
this.$cities.attr("disabled", null).easyDropDown('enable');
|
||||
|
||||
context.JK.dropdown(this.$cities);
|
||||
if(this.useEasyDropdown) {
|
||||
context.JK.dropdown(this.$cities);
|
||||
}
|
||||
},
|
||||
|
||||
regionListFailure: function (jqXHR, textStatus, errorThrown) {
|
||||
|
|
|
|||
|
|
@ -30,15 +30,15 @@
|
|||
e.preventDefault();
|
||||
|
||||
if (!context.JK.currentUserId) {
|
||||
window.location = '/client#/checkout_signin';
|
||||
window.location = '/client#/checkoutSignin';
|
||||
}
|
||||
else {
|
||||
app.user().done(function(user) {
|
||||
if(user.reuse_card) {
|
||||
window.location = '/client#/checkout_order';
|
||||
window.location = '/client#/checkoutOrder';
|
||||
}
|
||||
else {
|
||||
window.location = '/client#/checkout_payment';
|
||||
window.location = '/client#/checkoutPayment';
|
||||
}
|
||||
|
||||
})
|
||||
|
|
|
|||
|
|
@ -64,88 +64,3 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.order-panel {
|
||||
padding: 30px;
|
||||
|
||||
.order-header {
|
||||
h2 {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.order-content {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.order-left-page {
|
||||
float: left;
|
||||
width: 60%;
|
||||
|
||||
.payment-info-page {
|
||||
padding: 5px;
|
||||
|
||||
.info-caption-link {
|
||||
.caption-text {
|
||||
float: left;
|
||||
}
|
||||
.caption-link {
|
||||
float: left;
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.address-info {
|
||||
width: 50%;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.payment-method-info {
|
||||
width: 50%;
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
.order-items-page {
|
||||
padding: 5px;
|
||||
|
||||
.cart-item-caption {
|
||||
width: 50%;
|
||||
text-align: left;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.cart-item-caption#header {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.cart-item-price {
|
||||
width: 25%;
|
||||
text-align: right;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.cart-item-quantity {
|
||||
width: 25%;
|
||||
text-align: right;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.cart-items {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.cart-item {
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.order-right-page {
|
||||
float: right;
|
||||
width: 35%;
|
||||
text-align: center;
|
||||
|
||||
.order-total {
|
||||
color: #ed3618;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,204 @@
|
|||
@import "client/common.css.scss";
|
||||
#checkoutOrderScreen {
|
||||
|
||||
|
||||
p {
|
||||
font-size:12px;
|
||||
margin:0;
|
||||
}
|
||||
|
||||
.payment-prompt {
|
||||
color:white;
|
||||
line-height:125%;
|
||||
}
|
||||
|
||||
h2 {
|
||||
color:white;
|
||||
background-color:#4d4d4d;
|
||||
font-weight:normal;
|
||||
margin: 0 0 10px 0;
|
||||
font-size:14px;
|
||||
padding: 3px 0 3px 10px;
|
||||
height: 14px;
|
||||
line-height: 14px;
|
||||
vertical-align: middle;
|
||||
text-align:left;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.action-bar {
|
||||
margin-top:20px;
|
||||
}
|
||||
|
||||
.line {
|
||||
margin:10px 0 10px;
|
||||
border-width:0 0 1px 0;
|
||||
border-color:#ccc;
|
||||
border-style:solid;
|
||||
}
|
||||
|
||||
#checkout-info-help {
|
||||
margin-right:1px;
|
||||
}
|
||||
|
||||
.billing-info-item {
|
||||
margin-bottom:3px;
|
||||
}
|
||||
|
||||
.country {
|
||||
margin-left:15px;
|
||||
}
|
||||
.billing-address {
|
||||
margin-bottom:20px;
|
||||
}
|
||||
.order-panel {
|
||||
padding: 30px;
|
||||
min-width:730px;
|
||||
|
||||
.place-order {
|
||||
font-size: 14px;
|
||||
padding: 1px 3px;
|
||||
line-height: 15px;
|
||||
}
|
||||
|
||||
.place-order-center {
|
||||
text-align:center;
|
||||
margin:20px 0 20px;
|
||||
}
|
||||
|
||||
.change-payment-info {
|
||||
position:absolute;
|
||||
font-size:12px;
|
||||
left:180px;
|
||||
}
|
||||
|
||||
.billing-caption {
|
||||
margin-bottom:5px;
|
||||
float:left;
|
||||
position:relative;
|
||||
}
|
||||
.order-header {
|
||||
h2 {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.shipping-address {
|
||||
display:none;
|
||||
}
|
||||
|
||||
.order-help {
|
||||
margin:20px 0 30px;
|
||||
}
|
||||
.order-summary {
|
||||
padding:0 20px;
|
||||
|
||||
.billing-caption {
|
||||
float:none;
|
||||
margin-bottom:10px;
|
||||
}
|
||||
}
|
||||
.order-items-header {
|
||||
float:left;
|
||||
margin-bottom:5px;
|
||||
}
|
||||
|
||||
.order-items-value {
|
||||
float:right;
|
||||
}
|
||||
|
||||
.order-content {
|
||||
margin-top: 20px;
|
||||
background-color:#262626;
|
||||
}
|
||||
|
||||
.order-left-page {
|
||||
float: left;
|
||||
width: 65%;
|
||||
background-color:#262626;
|
||||
border-width:0 1px 0 0;
|
||||
border-style:solid;
|
||||
border-color:#333;
|
||||
@include border_box_sizing;
|
||||
|
||||
.payment-info-page {
|
||||
|
||||
.info-caption-link {
|
||||
.caption-text {
|
||||
float: left;
|
||||
}
|
||||
.caption-link {
|
||||
float: left;
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.address-info {
|
||||
width: 50%;
|
||||
float: left;
|
||||
padding:0 10px;
|
||||
@include border_box_sizing;
|
||||
margin-bottom:30px;
|
||||
}
|
||||
|
||||
.payment-method-info {
|
||||
width: 50%;
|
||||
float: left;
|
||||
padding:0 10px;
|
||||
@include border_box_sizing;
|
||||
}
|
||||
}
|
||||
.order-items-page {
|
||||
.cart-item-caption {
|
||||
width: 50%;
|
||||
text-align: left;
|
||||
float: left;
|
||||
margin-bottom:10px;
|
||||
@include border_box_sizing;
|
||||
}
|
||||
|
||||
.cart-item-price {
|
||||
width: 25%;
|
||||
text-align: right;
|
||||
float: left;
|
||||
padding:0 10px;
|
||||
margin-bottom:10px;
|
||||
@include border_box_sizing;
|
||||
}
|
||||
|
||||
.cart-item-quantity {
|
||||
width: 10%;
|
||||
text-align: right;
|
||||
float: left;
|
||||
padding:0 10px;
|
||||
margin-bottom:10px;
|
||||
@include border_box_sizing;
|
||||
}
|
||||
|
||||
.cart-items {
|
||||
margin-top: 10px;
|
||||
padding-left:10px;
|
||||
}
|
||||
|
||||
.cart-item {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.no-cart-items {
|
||||
}
|
||||
}
|
||||
}
|
||||
.order-right-page {
|
||||
float: left;
|
||||
width: 35%;
|
||||
text-align: left;
|
||||
background-color:#262626;
|
||||
@include border_box_sizing;
|
||||
|
||||
.order-total {
|
||||
color: #ed3618;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
.payment-wrapper {
|
||||
padding:10px 30px;
|
||||
min-width:600px;
|
||||
}
|
||||
|
||||
p {
|
||||
|
|
@ -41,6 +42,12 @@
|
|||
|
||||
input[type="text"], input[type="password"] {
|
||||
width: 90%;
|
||||
@include border_box_sizing;
|
||||
}
|
||||
|
||||
select#billing-country {
|
||||
width:90%;
|
||||
@include border_box_sizing;
|
||||
}
|
||||
|
||||
&.signed-in {
|
||||
|
|
@ -53,6 +60,21 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
&.not-signed-in {
|
||||
.row.second {
|
||||
.left-side {
|
||||
display:none;
|
||||
}
|
||||
.right-side {
|
||||
width:100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#divShippingFirstName, #divShippingLastName {
|
||||
display:none;
|
||||
}
|
||||
|
||||
.row {
|
||||
|
||||
margin-top:20px;
|
||||
|
|
@ -87,6 +109,23 @@
|
|||
float: left;
|
||||
@include border_box_sizing;
|
||||
}
|
||||
|
||||
div.terms-of-service.ichecbuttons {
|
||||
margin-left:5px;
|
||||
.icheckbox_minimal {
|
||||
|
||||
float: left;
|
||||
display: block;
|
||||
margin: 5px 5px 0 0;
|
||||
}
|
||||
}
|
||||
.terms-of-service-label-holder {
|
||||
font-size:12px;
|
||||
line-height:18px;
|
||||
top:4px;
|
||||
position:relative;
|
||||
float:left;
|
||||
}
|
||||
}
|
||||
|
||||
.hint {
|
||||
|
|
@ -131,11 +170,20 @@
|
|||
@include border_box_sizing;
|
||||
}
|
||||
|
||||
.save-card-checkbox {
|
||||
.save-card-checkbox, .reuse-existing-card-checkbox {
|
||||
float:left;
|
||||
display:block;
|
||||
margin-right:5px;
|
||||
}
|
||||
|
||||
label[for="reuse-existing-card"], label[for="save-card"] {
|
||||
line-height: 18px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.reuse-existing-card-helper {
|
||||
margin-bottom:10px;
|
||||
}
|
||||
}
|
||||
|
||||
.shipping-address {
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@
|
|||
*= require ./checkout
|
||||
*= require ./checkout_signin
|
||||
*= require ./checkout_payment
|
||||
*= require ./checkout_order
|
||||
*= require ./genreSelector
|
||||
*= require ./sessionList
|
||||
*= require ./searchResults
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ $ColorLinkHover: #82AEAF;
|
|||
$ColorSidebarText: #a0b9bd;
|
||||
$ColorScreenBackground: lighten($ColorUIBackground, 10%);
|
||||
$ColorTextBoxBackground: #c5c5c5;
|
||||
$ColorTextBoxDisabledBackground: #999;
|
||||
$ColorRecordingBackground: #471f18;
|
||||
|
||||
$ColorTextHighlight: white;
|
||||
|
|
|
|||
|
|
@ -222,6 +222,10 @@
|
|||
border:none;
|
||||
-webkit-box-shadow: inset 2px 2px 3px 0px #888;
|
||||
box-shadow: inset 2px 2px 3px 0px #888;
|
||||
|
||||
&:disabled {
|
||||
background-color: $ColorTextBoxDisabledBackground;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -322,6 +322,10 @@ input[type="text"], input[type="password"]{
|
|||
border:none;
|
||||
padding:3px;
|
||||
font-size:15px;
|
||||
|
||||
&:disabled {
|
||||
background-color: $ColorTextBoxDisabledBackground;
|
||||
}
|
||||
}
|
||||
|
||||
textarea {
|
||||
|
|
|
|||
|
|
@ -8,10 +8,18 @@ class ApiRecurlyController < ApiController
|
|||
def create_account
|
||||
|
||||
billing_info = params[:billing_info]
|
||||
shipping_info = params[:shipping_info]
|
||||
# should we let the user reuse this card next time?
|
||||
reuse_card_next_time = params[:reuse_card_next_time] == "true"
|
||||
# should we update the card info, or use what's on file this time?
|
||||
reuse_card_this_time = params[:reuse_card_this_time] == "true"
|
||||
# terms of service accepted?
|
||||
terms_of_service = params[:terms_of_service] == "true"
|
||||
|
||||
|
||||
if current_user
|
||||
# keep reuse card up-to-date
|
||||
User.where(id: current_user.id).update_all(reuse_card: params[:reuse_card])
|
||||
User.where(id: current_user.id).update_all(reuse_card: params[:reuse_card_next_time])
|
||||
else
|
||||
options = {
|
||||
remote_ip: request.remote_ip,
|
||||
|
|
@ -20,17 +28,17 @@ class ApiRecurlyController < ApiController
|
|||
email: params[:email],
|
||||
password: params[:password],
|
||||
password_confirmation: params[:password],
|
||||
terms_of_service: params[:terms_of_service],
|
||||
instruments: [{ :instrument_id => 'other', :proficiency_level => 3, :priority => 1 }],
|
||||
terms_of_service: terms_of_service,
|
||||
instruments: [{ :instrument_id => 'other', :proficiency_level => 1, :priority => 1 }],
|
||||
birth_date: nil,
|
||||
location: { :country => billing_info[:country], :state => billing_info[:state], :city => billing_info[:city]},
|
||||
musician: true,
|
||||
recaptcha_failed: false,
|
||||
skip_recaptcha: true,
|
||||
invited_user: nil,
|
||||
fb_signup: nil,
|
||||
signup_confirm_url: ApplicationHelper.base_uri(request) + "/confirm",
|
||||
any_user: any_user,
|
||||
reuse_card: params[:reuse_card]
|
||||
reuse_card: reuse_card_next_time
|
||||
}
|
||||
|
||||
user = UserManager.new.signup(options)
|
||||
|
|
@ -45,7 +53,14 @@ class ApiRecurlyController < ApiController
|
|||
end
|
||||
|
||||
begin
|
||||
@account = @client.find_or_create_account(current_user, billing_info)
|
||||
billing_info[:ip_address] = request.remote_ip if billing_info
|
||||
if reuse_card_this_time
|
||||
# do not attempt to update any billing/shipping info unless the user re-inputs their info!
|
||||
@account = @client.get_account(current_user)
|
||||
else
|
||||
@account = @client.find_or_create_account(current_user, billing_info)
|
||||
end
|
||||
|
||||
render :json=>account_json(@account)
|
||||
rescue RecurlyClientError => x
|
||||
render json: { :message => x.inspect, errors: x.errors }, :status => 404
|
||||
|
|
@ -61,7 +76,7 @@ class ApiRecurlyController < ApiController
|
|||
|
||||
# get Recurly account
|
||||
def get_account
|
||||
@account=@client.get_account(current_user)
|
||||
@account = @client.get_account(current_user)
|
||||
|
||||
render :json=>account_json(@account)
|
||||
rescue RecurlyClientError => e
|
||||
|
|
@ -79,9 +94,11 @@ class ApiRecurlyController < ApiController
|
|||
# get Billing Information
|
||||
def billing_info
|
||||
@account = @client.get_account(current_user)
|
||||
# @billing = @account.billing_info
|
||||
# @billing ||= @account
|
||||
render :json=> account_json(@account)
|
||||
if @account
|
||||
render :json=> account_json(@account)
|
||||
else
|
||||
render :json=> {}, :status => 404
|
||||
end
|
||||
rescue RecurlyClientError => x
|
||||
render json: { message: x.inspect, errors: x.errors}, :status => 404
|
||||
end
|
||||
|
|
@ -96,33 +113,20 @@ class ApiRecurlyController < ApiController
|
|||
|
||||
def place_order
|
||||
error=nil
|
||||
puts "PLACING ORDER #{params.inspect}"
|
||||
response = {jam_tracks:[]}
|
||||
|
||||
# 1st confirm that all specified JamTracks exist
|
||||
jam_tracks = []
|
||||
current_user.shopping_carts.each do |shopping_cart|
|
||||
jam_track = shopping_cart.cart_product
|
||||
|
||||
params[:jam_tracks].each do |jam_track_id|
|
||||
jam_track = JamTrack.where("id=?", jam_track_id).first
|
||||
if jam_track
|
||||
jam_tracks << jam_track
|
||||
else
|
||||
error="JamTrack not found for '#{jam_track_id}'"
|
||||
break
|
||||
end
|
||||
# if shopping_cart has any marked_for_redeem, then we zero out the price by passing in 'free'
|
||||
# NOTE: shopping_carts have the idea of quantity, but you should only be able to buy at most one JamTrack. So anything > 0 is considered free for a JamTrack
|
||||
|
||||
jam_track_right = @client.place_order(current_user, jam_track, shopping_cart)
|
||||
# build up the response object with JamTracks that were purchased.
|
||||
# if this gets more complicated, we should switch to RABL
|
||||
response[:jam_tracks] << {name: jam_track.name, id: jam_track.id, jam_track_right_id: jam_track_right.id, version: jam_track.version}
|
||||
end
|
||||
|
||||
# then buy each
|
||||
unless error
|
||||
jam_tracks.each do |jam_track|
|
||||
jam_track_right = @client.place_order(current_user, jam_track)
|
||||
# build up the response object with JamTracks that were purchased.
|
||||
# if this gets more complicated, we should switch to RABL
|
||||
response[:jam_tracks] << {name: jam_track.name, id: jam_track.id, jam_track_right_id: jam_track_right.id, version: jam_track.version}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if error
|
||||
render json: { errors: {message:error}}, :status => 404
|
||||
else
|
||||
|
|
@ -138,16 +142,21 @@ private
|
|||
end
|
||||
|
||||
def account_json(account)
|
||||
|
||||
billing_info = account.billing_info.nil? ? nil : {
|
||||
:first_name => account.billing_info.first_name,
|
||||
:last_name => account.billing_info.last_name,
|
||||
:address1 => account.billing_info.address1,
|
||||
:address2 => account.billing_info.address2,
|
||||
:city => account.billing_info.city,
|
||||
:state => account.billing_info.state,
|
||||
:zip => account.billing_info.zip,
|
||||
:country => account.billing_info.country,
|
||||
:last_four => account.billing_info.last_four
|
||||
}
|
||||
|
||||
{
|
||||
:first_name => account.first_name,
|
||||
:last_name => account.last_name,
|
||||
:email => account.email,
|
||||
:address1 => account.billing_info ? account.billing_info.address1 : nil,
|
||||
:address2 => account.billing_info ? account.billing_info.address2 : nil,
|
||||
:city => account.billing_info ? account.billing_info.city : nil,
|
||||
:state => account.billing_info ? account.billing_info.state : nil,
|
||||
:zip => account.billing_info ? account.billing_info.zip : nil,
|
||||
:country => account.billing_info ? account.billing_info.country : nil
|
||||
billing_info: billing_info
|
||||
}
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,11 @@ class ApiShoppingCartsController < ApiController
|
|||
raise StateError, "Invalid JamTrack."
|
||||
end
|
||||
|
||||
@cart = ShoppingCart.create any_user, jam_track
|
||||
ShoppingCart.transaction do
|
||||
mark_redeem = ShoppingCart.user_has_redeemable_jam_track?(any_user)
|
||||
@cart = ShoppingCart.create(any_user, jam_track, 1, mark_redeem)
|
||||
end
|
||||
|
||||
|
||||
if @cart.errors.any?
|
||||
response.status = :unprocessable_entity
|
||||
|
|
@ -46,7 +50,21 @@ class ApiShoppingCartsController < ApiController
|
|||
@cart = any_user.shopping_carts.find_by_id(params[:id])
|
||||
raise StateError, "Invalid Cart." if @cart.nil?
|
||||
|
||||
@cart.destroy
|
||||
ShoppingCart.transaction do
|
||||
@cart.destroy
|
||||
|
||||
# check if we should move the redemption
|
||||
mark_redeem = ShoppingCart.user_has_redeemable_jam_track?(any_user)
|
||||
|
||||
carts = any_user.shopping_carts
|
||||
|
||||
# if we find any carts on the account, mark one redeemable
|
||||
if mark_redeem && carts.length > 0
|
||||
carts[0].redeem(mark_redeem)
|
||||
carts[0].save
|
||||
end
|
||||
end
|
||||
|
||||
respond_with responder: ApiResponder, :status => 204
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,10 @@ if @user == current_user
|
|||
geoiplocation.info if geoiplocation
|
||||
end
|
||||
|
||||
node :free_jamtrack do |user|
|
||||
Rails.application.config.one_free_jamtrack_per_user && user.has_redeemable_jamtrack
|
||||
end
|
||||
|
||||
node :mods do |user|
|
||||
user.mods_json
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,154 @@
|
|||
div layout="screen" layout-id="checkoutOrder" id="checkoutOrderScreen" class="screen secondary"
|
||||
.content
|
||||
.content-head
|
||||
.content-icon= image_tag("content/icon_shopping_cart.png", {:height => 19, :width => 19})
|
||||
h1 check out
|
||||
= render "screen_navigation"
|
||||
.content-body
|
||||
#order_error.error.hidden
|
||||
.content-body-scroller
|
||||
.content-wrapper
|
||||
.checkout-navigation-bar
|
||||
.order-panel
|
||||
.payment-wrapper
|
||||
p.payment-prompt.hidden
|
||||
| Please review your order, and if everything looks correct, click the PLACE YOUR ORDER button. Thank you!
|
||||
p.empty-cart-prompt.hidden
|
||||
| You have nothing in your cart. You can go browse for JamTracks
|
||||
a href="/client#/jamtrack" here
|
||||
| .
|
||||
.order-content
|
||||
|
||||
|
||||
.clearall
|
||||
.action-bar
|
||||
|
||||
.right
|
||||
a.button-grey href="#" id="checkout-info-help" HELP
|
||||
a.button-grey.back href="#" BACK
|
||||
a.button-orange.place-order href="#" PLACE YOUR ORDER
|
||||
.clearall
|
||||
.thanks-panel
|
||||
h2 Thank you for your order!
|
||||
br
|
||||
.thanks-detail We'll send you an email confirming your order shortly.
|
||||
br
|
||||
.thanks-detail.jam-tracks-in-browser.hidden
|
||||
| To play your purchased JamTrack, launch the JamKazam application and open the JamTrack while in a session.
|
||||
.thanks-detail.purchased-jam-track.hidden
|
||||
h2.purchased-jam-track-header Downloading Your Purchased JamTracks
|
||||
span Each JamTrack will be downloaded sequentially.
|
||||
br
|
||||
span.notice Note that you do not have to wait for this to complete in order to use your JamTrack later.
|
||||
br.clear
|
||||
ul.purchased-list
|
||||
|
||||
|
||||
|
||||
script type='text/template' id='template-order-content'
|
||||
.order-left-page
|
||||
.payment-info-page
|
||||
h2 ADDRESS & PAYMENT
|
||||
.address-info
|
||||
.billing-address
|
||||
.billing-caption
|
||||
| BILLING ADDRESS:
|
||||
a.change-payment-info href="#" change
|
||||
.clearall
|
||||
.billing-info-item= "{{data.billing_info.address1}}"
|
||||
.billing-info-item= "{{data.billing_info.address2}}"
|
||||
.billing-info-item
|
||||
| {{data.billing_info.city}}, {{data.billing_info.state}} {{data.billing_info.zip}}
|
||||
span.country= "{{data.billing_info.country}}"
|
||||
.shipping-address
|
||||
.billing-caption
|
||||
| SHIPPING ADDRESS:
|
||||
a.change-payment-info href="#" change
|
||||
.clearall
|
||||
= "{% if (data.shipping_as_billing) { %}"
|
||||
.billing-info-item Same as billing address
|
||||
= "{% } else { %}"
|
||||
.billing-info-item= "{{data.shipping_info.address1}}"
|
||||
.billing-info-item= "{{data.shipping_info.address2}}"
|
||||
.billing-info-item
|
||||
| {{data.shipping_info.city}}, {{data.shipping_info.state}} {{data.shipping_info.zip}}
|
||||
span.country= "{{data.shipping_info.country}}"
|
||||
= "{% } %}"
|
||||
br
|
||||
.payment-method-info
|
||||
.billing-caption
|
||||
| PAYMENT METHOD:
|
||||
a.change-payment-info href="#" change
|
||||
.clearall
|
||||
|
||||
/= image_tag ''
|
||||
="Credit card ending {{data.billing_info.last_four}}"
|
||||
|
||||
.clearall
|
||||
.order-items-page
|
||||
h2 ORDER DETAILS
|
||||
.cart-items
|
||||
.cart-item-caption
|
||||
span YOUR ORDER INCLUDES:
|
||||
.cart-item-price
|
||||
span PRICE
|
||||
.cart-item-quantity
|
||||
span QUANTITY
|
||||
.clearall
|
||||
= "{% if (data.carts.length == 0) { %}"
|
||||
.no-cart-items You have no orders now.
|
||||
= "{% } %}"
|
||||
= "{% _.each(data.carts, function(cart) { %}"
|
||||
.cart-item cart-id="{{cart.id}}"
|
||||
.cart-item-caption
|
||||
= "{{cart.cart_type}}: {{cart.product_info.name}}"
|
||||
.cart-item-price
|
||||
= "$ {{Number(cart.product_info.total_price).toFixed(2)}}"
|
||||
.cart-item-quantity
|
||||
= "{{cart.quantity}}"
|
||||
.clearall
|
||||
= "{% }); %}"
|
||||
.clearall
|
||||
.order-right-page
|
||||
h2 PLACE ORDER
|
||||
.recurly-data.hidden
|
||||
= "{% _.each(data.carts, function(cart) { %}"
|
||||
.plan data-plan-code="{{cart.product_info.plan_code}}"
|
||||
input data-recurly="plan" type="text" value="{{cart.product_info.plan_code}}"
|
||||
= "{% }); %}"
|
||||
.order-summary
|
||||
.place-order-center
|
||||
a.button-orange.place-order href="#" PLACE YOUR ORDER
|
||||
.clearall
|
||||
|
||||
.billing-caption ORDER SUMMARY:
|
||||
.order-items-header Order items:
|
||||
.order-items-value ${{data.sub_total}}
|
||||
.clearall
|
||||
.order-items-header Shipping & handling:
|
||||
.order-items-value $0.00
|
||||
.clearall
|
||||
.line
|
||||
.order-items-header Total before tax:
|
||||
.order-items-value ${{data.sub_total}}
|
||||
.clearall
|
||||
.order-items-header.taxes Taxes:
|
||||
.order-items-value.taxes Calculating...
|
||||
.clearall
|
||||
.line
|
||||
.order-items-header.order-total Order total:
|
||||
.order-items-value.order-total Calculating...
|
||||
.clearall
|
||||
.order-help
|
||||
span By placing your order, you agree to JamKazam's
|
||||
'
|
||||
a href="http://www.jamkazam.com/corp/terms" rel="external" terms of service
|
||||
'
|
||||
span and
|
||||
'
|
||||
a href="http://www.jamkazam.com/corp/returns" rel="external" returns policy
|
||||
span .
|
||||
.clearall
|
||||
|
||||
script type='text/template' id='template-purchased-jam-track'
|
||||
li data-jam-track-id="{{data.jam_track_id}}"
|
||||
|
|
@ -1,20 +1,22 @@
|
|||
div layout="screen" layout-id="checkout_payment" id="checkoutPaymentScreen" class="screen secondary no-login-required"
|
||||
div layout="screen" layout-id="checkoutPayment" id="checkoutPaymentScreen" class="screen secondary no-login-required"
|
||||
.content
|
||||
.content-head
|
||||
.content-icon= image_tag("content/icon_shopping_cart.png", {:height => 19, :width => 19})
|
||||
h1 check out
|
||||
= render "screen_navigation"
|
||||
.content-body
|
||||
#order_error.error.hidden
|
||||
#payment_error.error.hidden
|
||||
.content-body-scroller
|
||||
.content-wrapper
|
||||
.checkout-navigation-bar
|
||||
.payment-wrapper
|
||||
p.payment-prompt
|
||||
| Please enter you billing address and payment information below. You will not be billed for your first JamTrack, which is 100% free.
|
||||
p.payment-prompt.free-jamtrack.hidden
|
||||
| Please enter your billing address and payment information below. You will not be billed for your first JamTrack, which is 100% free.
|
||||
| But we need this data to prevent fraud/abuse of those who would create multiple accounts to collect multiple free JamTracks.
|
||||
| You will not be billed for any charges of any kind without your explicit authorization.
|
||||
| There are no "hidden" charges or fees, thank you!
|
||||
p.payment-prompt.no-free-jamtrack.hidden
|
||||
| Please enter your billing address and payment information below.
|
||||
|
||||
form class="payment-info" id="checkout-payment-info"
|
||||
.row.first
|
||||
|
|
@ -67,37 +69,49 @@ div layout="screen" layout-id="checkout_payment" id="checkoutPaymentScreen" clas
|
|||
.billing-label
|
||||
label for="billing-country" Country:
|
||||
.billing-value
|
||||
input type="text" id="billing-country"
|
||||
select id="billing-country"
|
||||
option value="US" US
|
||||
.clearall
|
||||
.right-side
|
||||
.payment-method
|
||||
h2.payment-method-caption PAYMENT METHOD
|
||||
#divCardName.field
|
||||
.new-card-info
|
||||
#divCardName.field.hidden
|
||||
.card-label
|
||||
label for="card-name" Name of Card:
|
||||
.card-value
|
||||
input type="text" id="card-name"
|
||||
.clearall
|
||||
#divCardNumber.field
|
||||
.card-label
|
||||
label for="card-number" Card Number:
|
||||
.card-value
|
||||
input type="text" id="card-number"
|
||||
.clearall
|
||||
#divCardExpiry.field
|
||||
.card-label Expiration Date:
|
||||
.card-value
|
||||
=date_select("card", "expire-date", use_two_digit_numbers: true, discard_day: true, :start_year => Time.now.year, :end_year => Time.now.year + 18, :order => [:month, :day, :year], :default => -25.years.from_now, :html => {:class => "account-profile-birthdate", :id => "card-expiry"})
|
||||
.clearall
|
||||
#divCardVerify.field
|
||||
.card-label
|
||||
label for="card-verify"
|
||||
| CVV Code:
|
||||
.hint.cvv
|
||||
| (back of card)
|
||||
.card-value
|
||||
input type="text" id="card-verify"
|
||||
.clearall
|
||||
.reuse-existing-card
|
||||
.card-label
|
||||
label for="card-name" Name of Card:
|
||||
.card-value
|
||||
input type="text" id="card-name"
|
||||
.clearall
|
||||
#divCardNumber.field
|
||||
.card-label
|
||||
label for="card-number" Card Number:
|
||||
.card-value
|
||||
input type="text" id="card-number"
|
||||
.clearall
|
||||
#divCardExpiry.field
|
||||
.card-label Expiration Date:
|
||||
.card-value
|
||||
=date_select("card", "expire-date", use_two_digit_numbers: true, discard_day: true, :start_year => Time.now.year, :end_year => Time.now.year + 18, :order => [:month, :day, :year], :default => -25.years.from_now, :html => {:class => "account-profile-birthdate", :id => "card-expiry"})
|
||||
.clearall
|
||||
#divCardVerify.field
|
||||
.card-label
|
||||
label for="card-verify"
|
||||
| CVV Code:
|
||||
.hint.cvv
|
||||
| (back-of-card)
|
||||
.card-value
|
||||
input type="text" id="card-verify"
|
||||
.clearall
|
||||
.reuse-existing-card-checkbox.ichecbuttons
|
||||
input type="checkbox" id="reuse-existing-card" name="reuse-existing-card" checked="checked"
|
||||
.reuse-existing-card-helper
|
||||
label for="reuse-existing-card"
|
||||
| Use card ending in
|
||||
span.existing-card-ends-with
|
||||
.clearall
|
||||
.card-label
|
||||
.card-value
|
||||
.save-card-checkbox.ichecbuttons
|
||||
|
|
@ -108,7 +122,7 @@ div layout="screen" layout-id="checkout_payment" id="checkoutPaymentScreen" clas
|
|||
.clearall
|
||||
.clearall
|
||||
.row.second
|
||||
.left-side
|
||||
left-side.hidden
|
||||
.shipping-address
|
||||
h2.shipping-address-label SHIPPING ADDRESS
|
||||
.shipping-as-billing.ichecbuttons
|
||||
|
|
@ -180,6 +194,14 @@ div layout="screen" layout-id="checkout_payment" id="checkoutPaymentScreen" clas
|
|||
.account-value
|
||||
input name="password" type="password"
|
||||
.clearall
|
||||
#divJamKazamTos.field
|
||||
.terms-of-service.ichecbuttons
|
||||
input type="checkbox" name="terms-of-service"
|
||||
.terms-of-service-label-holder
|
||||
label for="terms-of-service"
|
||||
| I have read and agree to the JamKazam
|
||||
a rel="external" href=corp_terms_path terms of service
|
||||
.clearall
|
||||
.clearall
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
div layout="screen" layout-id="checkout_signin" id="checkoutSignInScreen" class="screen secondary no-login-required"
|
||||
div layout="screen" layout-id="checkoutSignin" id="checkoutSignInScreen" class="screen secondary no-login-required"
|
||||
.content
|
||||
.content-head
|
||||
.content-icon= image_tag("content/icon_shopping_cart.png", {:height => 19, :width => 19})
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@
|
|||
<%= render "shopping_cart" %>
|
||||
<%= render "checkout_signin" %>
|
||||
<%= render "checkout_payment" %>
|
||||
<%= render "checkout_order" %>
|
||||
<%= render "order" %>
|
||||
<%= render "feed" %>
|
||||
<%= render "bands" %>
|
||||
|
|
@ -241,7 +242,10 @@
|
|||
checkoutSignInScreen.initialize();
|
||||
|
||||
var checkoutPaymentScreen = new JK.CheckoutPaymentScreen(JK.app);
|
||||
checkoutPaymentScreen.initialize();
|
||||
checkoutPaymentScreen.initialize();
|
||||
|
||||
var checkoutOrderScreen = new JK.CheckoutOrderScreen(JK.app);
|
||||
checkoutOrderScreen.initialize();
|
||||
|
||||
// var OrderScreen = new JK.OrderScreen(JK.app);
|
||||
// OrderScreen.initialize();
|
||||
|
|
|
|||
|
|
@ -35,5 +35,7 @@
|
|||
<body class="jam" data-client-type="<%= @nativeClient ? 'client' : 'browser' %>">
|
||||
<%= yield %>
|
||||
<%= render "shared/ga" %>
|
||||
<%= render "shared/recurly" %>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
script src="https://js.recurly.com/v3/recurly.js"
|
||||
|
||||
javascript:
|
||||
recurly.configure(gon.global.recurly_public_api_key)
|
||||
|
|
@ -318,5 +318,6 @@ if defined?(Bundler)
|
|||
config.show_jamblaster_kickstarter_link = true
|
||||
config.metronome_available = true
|
||||
config.backing_tracks_available = true
|
||||
config.one_free_jamtrack_per_user = true
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -10,4 +10,6 @@ Gon.global.influxdb_port = Rails.application.config.influxdb_port
|
|||
Gon.global.influxdb_database = Rails.application.config.influxdb_database
|
||||
Gon.global.influxdb_username = Rails.application.config.influxdb_unsafe_username
|
||||
Gon.global.influxdb_password = Rails.application.config.influxdb_unsafe_password
|
||||
Gon.global.recurly_public_api_key = Rails.application.config.recurly_public_api_key
|
||||
Gon.global.one_free_jamtrack_per_user = Rails.application.config.one_free_jamtrack_per_user
|
||||
Gon.global.env = Rails.env
|
||||
|
|
|
|||
|
|
@ -26,8 +26,12 @@ class UserManager < BaseManager
|
|||
fb_signup = options[:fb_signup]
|
||||
signup_confirm_url = options[:signup_confirm_url]
|
||||
affiliate_referral_id = options[:affiliate_referral_id]
|
||||
recaptcha_failed=(fb_signup) ? false : !@google_client.verify_recaptcha(options[:recaptcha_response])
|
||||
|
||||
any_user = options[:any_user]
|
||||
recaptcha_failed = false
|
||||
unless options[:skip_recaptcha] # allow callers to opt-of recaptcha
|
||||
recaptcha_failed = fb_signup ? false : !@google_client.verify_recaptcha(options[:recaptcha_response])
|
||||
end
|
||||
|
||||
user = User.new
|
||||
|
||||
# check if we have disabled open signup for this site. open == invited users can still get in
|
||||
|
|
@ -62,11 +66,9 @@ class UserManager < BaseManager
|
|||
invited_user: invited_user,
|
||||
fb_signup: fb_signup,
|
||||
signup_confirm_url: signup_confirm_url,
|
||||
affiliate_referral_id: affiliate_referral_id)
|
||||
|
||||
|
||||
return user
|
||||
#end
|
||||
affiliate_referral_id: affiliate_referral_id,
|
||||
any_user: any_user)
|
||||
user
|
||||
end
|
||||
|
||||
def signup_confirm(signup_token, remote_ip=nil)
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ describe ApiRecurlyController, :type=>:controller do
|
|||
|
||||
it "should send correct error" do
|
||||
@billing_info[:number]='121'
|
||||
post :create_account, {:format => 'json', :billing_info=>@billing_info}
|
||||
post :create_account, {:format => 'json', :billing_info=>@billing_info, reuse_card_this_time: false, reuse_card_next_time: false}
|
||||
response.status.should == 404
|
||||
body = JSON.parse(response.body)
|
||||
body['errors'].should have(1).items
|
||||
|
|
@ -43,36 +43,39 @@ describe ApiRecurlyController, :type=>:controller do
|
|||
end
|
||||
|
||||
it "should create account" do
|
||||
post :create_account, {:format => 'json'}
|
||||
response.should be_success
|
||||
post :create_account, {:format => 'json',billing_info: @billing_info, reuse_card_this_time: false, reuse_card_next_time: false}
|
||||
response.should be_success
|
||||
body = JSON.parse(response.body)
|
||||
response.should be_success
|
||||
body['billing_info']['first_name'].should eq(@user.first_name)
|
||||
end
|
||||
|
||||
it "should retrieve account" do
|
||||
post :create_account, {:format => 'json'}
|
||||
it "should retrieve account with no billing info" do
|
||||
post :create_account, {:format => 'json', reuse_card_this_time: false, reuse_card_next_time: false}
|
||||
response.should be_success
|
||||
|
||||
get :get_account
|
||||
body = JSON.parse(response.body)
|
||||
response.should be_success
|
||||
body['email'].should eq(@user.email)
|
||||
body['billing_info'].should be_nil
|
||||
end
|
||||
|
||||
it "should update account" do
|
||||
post :create_account
|
||||
post :create_account, {:format => 'json', billing_info: @billing_info, reuse_card_this_time: false, reuse_card_next_time: false}
|
||||
response.should be_success
|
||||
body = JSON.parse(response.body)
|
||||
body['first_name'].should eq("Person")
|
||||
body['billing_info']['first_name'].should eq("Person")
|
||||
|
||||
@user.update_attribute(:first_name, "Thing")
|
||||
controller.current_user = @user
|
||||
put :update_account
|
||||
@billing_info[:first_name] = "Thing"
|
||||
put :update_account, {:format => 'json', billing_info: @billing_info}
|
||||
body = JSON.parse(response.body)
|
||||
body['first_name'].should eq("Thing")
|
||||
body['billing_info']['first_name'].should eq("Thing")
|
||||
|
||||
get :get_account, { :format => 'json'}
|
||||
response.should be_success
|
||||
body = JSON.parse(response.body)
|
||||
body['first_name'].should eq("Thing")
|
||||
body['billing_info']['first_name'].should eq("Thing")
|
||||
end
|
||||
|
||||
# Note: We don't have any subscriptions yet:
|
||||
|
|
@ -95,13 +98,13 @@ describe ApiRecurlyController, :type=>:controller do
|
|||
|
||||
# $enable_tracing = true
|
||||
|
||||
post :create_account
|
||||
post :create_account, {:format => 'json', billing_info: @billing_info, reuse_card_this_time: false, reuse_card_next_time: false}
|
||||
response.should be_success
|
||||
body = JSON.parse(response.body)
|
||||
body['first_name'].should eq("Person")
|
||||
body['billing_info']['first_name'].should eq("Person")
|
||||
@billing_info[:state] = "NE"
|
||||
|
||||
put :update_billing_info, {:format => 'json', :billing_info=>@billing_info}
|
||||
put :update_billing_info, {format: 'json', billing_info: @billing_info}
|
||||
|
||||
response.should be_success
|
||||
body = JSON.parse(response.body)
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ FactoryGirl.define do
|
|||
terms_of_service true
|
||||
subscribe_email true
|
||||
last_jam_audio_latency 5
|
||||
resue_card true
|
||||
reuse_card true
|
||||
|
||||
factory :fan do
|
||||
musician false
|
||||
|
|
|
|||
|
|
@ -0,0 +1,102 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe "Checkout", :js => true, :type => :feature, :capybara_feature => true do
|
||||
|
||||
let(:user) { FactoryGirl.create(:user) }
|
||||
let(:jamtrack_acdc_backinblack) { FactoryGirl.create(:jam_track, name: 'Back in Black', original_artist: 'AC/DC', sales_region: 'United States', make_track: true, plan_code: 'jamtrack-acdc-backinblack') }
|
||||
|
||||
before(:all) do
|
||||
Capybara.javascript_driver = :poltergeist
|
||||
Capybara.current_driver = Capybara.javascript_driver
|
||||
Capybara.default_wait_time = 30 # these tests are SLOOOOOW
|
||||
end
|
||||
|
||||
|
||||
before(:each) do
|
||||
ShoppingCart.delete_all
|
||||
JamTrack.delete_all
|
||||
JamTrackTrack.delete_all
|
||||
JamTrackLicensor.delete_all
|
||||
|
||||
stub_const("APP_CONFIG", web_config)
|
||||
end
|
||||
|
||||
|
||||
describe "Shopping" do
|
||||
|
||||
before(:each) do
|
||||
visit "/client#/jamtrack"
|
||||
find('h1', text: 'jamtracks')
|
||||
find('a', text: 'What is a JamTrack?')
|
||||
|
||||
jk_select('Any', '#jamtrack-find-form #jamtrack_availability')
|
||||
end
|
||||
|
||||
it "shows all JamTracks" do
|
||||
find_jamtrack jt_us
|
||||
find_jamtrack jt_ww
|
||||
find_jamtrack jt_rock
|
||||
end
|
||||
|
||||
it "filters with availability" do
|
||||
jk_select('Worldwide', '#jamtrack-find-form #jamtrack_availability')
|
||||
find_jamtrack jt_ww
|
||||
not_find_jamtrack jt_us
|
||||
not_find_jamtrack jt_rock
|
||||
end
|
||||
|
||||
it "filters with genre" do
|
||||
jk_select('Blues', '#jamtrack-find-form #jamtrack_genre')
|
||||
find_jamtrack jt_blues
|
||||
not_find_jamtrack jt_rock
|
||||
not_find_jamtrack jt_us
|
||||
not_find_jamtrack jt_ww
|
||||
end
|
||||
|
||||
it "filters with instrument" do
|
||||
jk_select('Electric Guitar', '#jamtrack-find-form #jamtrack_instrument')
|
||||
find_jamtrack jt_us
|
||||
find_jamtrack jt_ww
|
||||
find_jamtrack jt_rock
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe "Shopping Carts" do
|
||||
|
||||
before(:each) do
|
||||
visit "/client#/jamtrack"
|
||||
find('h1', text: 'jamtracks')
|
||||
find('a', text: 'What is a JamTrack?')
|
||||
|
||||
jk_select('Any', '#jamtrack-find-form #jamtrack_availability')
|
||||
end
|
||||
|
||||
it "adds/deletes JamTrack to/from Cart" do
|
||||
find("a.jamtrack-add-cart[data-jamtrack-id=\"#{jt_us.id}\"]").trigger(:click)
|
||||
|
||||
find('h1', text: 'shopping cart')
|
||||
find('.cart-item-caption', text: "JamTrack: #{jt_us.name}")
|
||||
find('.cart-item-price', text: "$ #{jt_us.price}")
|
||||
|
||||
find('a.button-orange', text: 'CONTINUE SHOPPING').trigger(:click)
|
||||
jk_select('Any', '#jamtrack-find-form #jamtrack_availability')
|
||||
find_jamtrack jt_us, {added_cart: true}
|
||||
|
||||
find('a.header-shopping-cart').trigger(:click)
|
||||
find("a.remove-cart").trigger(:click)
|
||||
find('a.button-orange', text: 'CONTINUE SHOPPING').trigger(:click)
|
||||
jk_select('Any', '#jamtrack-find-form #jamtrack_availability')
|
||||
|
||||
find_jamtrack jt_us
|
||||
|
||||
find("a.jamtrack-add-cart[data-jamtrack-id=\"#{jt_us.id}\"]").trigger(:click)
|
||||
find('a.button-orange', text: 'CONTINUE SHOPPING').trigger(:click)
|
||||
find("a.jamtrack-add-cart[data-jamtrack-id=\"#{jt_ww.id}\"]").trigger(:click)
|
||||
find('a.button-orange', text: 'CONTINUE SHOPPING').trigger(:click)
|
||||
|
||||
find('.shopping-sub-total', text: "Subtotal: $ #{jt_us.price + jt_ww.price}")
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
@ -78,6 +78,10 @@ def web_config
|
|||
def signing_job_queue_max_time
|
||||
20 # 20 seconds
|
||||
end
|
||||
|
||||
def one_free_jamtrack_per_user
|
||||
true
|
||||
end
|
||||
end
|
||||
klass.new
|
||||
end
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ FactoryGirl.define do
|
|||
state "NC"
|
||||
country "US"
|
||||
terms_of_service true
|
||||
resue_card true
|
||||
reuse_card true
|
||||
|
||||
|
||||
factory :admin do
|
||||
|
|
|
|||
Loading…
Reference in New Issue