* VRFS-3028 - switch to using Recurly Adjustments for JamTrack purchases
This commit is contained in:
parent
c230f57592
commit
e42b926a5e
|
|
@ -2,12 +2,9 @@ ActiveAdmin.register_page "Recurly Health" do
|
||||||
menu :parent => 'Misc'
|
menu :parent => 'Misc'
|
||||||
|
|
||||||
content :title => "Recurly Transaction Totals" do
|
content :title => "Recurly Transaction Totals" do
|
||||||
table_for Sale.check_integrity do
|
table_for Sale.check_integrity_of_jam_track_sales do
|
||||||
column "Total", :total
|
column "Total", :total
|
||||||
column "Unknown", :not_known
|
|
||||||
column "Successes", :succeeded
|
column "Successes", :succeeded
|
||||||
column "Failures", :failed
|
|
||||||
column "Refunds", :refunded
|
|
||||||
column "Voids", :voided
|
column "Voids", :voided
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -274,4 +274,5 @@ recording_client_metadata.sql
|
||||||
preview_support_mp3.sql
|
preview_support_mp3.sql
|
||||||
jam_track_duration.sql
|
jam_track_duration.sql
|
||||||
sales.sql
|
sales.sql
|
||||||
show_whats_next_count.sql
|
show_whats_next_count.sql
|
||||||
|
recurly_adjustments.sql
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
ALTER TABLE sale_line_items ADD COLUMN recurly_adjustment_uuid VARCHAR(500);
|
||||||
|
ALTER TABLE sale_line_items ADD COLUMN recurly_adjustment_credit_uuid VARCHAR(500);
|
||||||
|
ALTER TABLE jam_track_rights ADD COLUMN recurly_adjustment_uuid VARCHAR(500);
|
||||||
|
ALTER TABLE jam_track_rights ADD COLUMN recurly_adjustment_credit_uuid VARCHAR(500);
|
||||||
|
ALTER TABLE sales ADD COLUMN recurly_invoice_id VARCHAR(500) UNIQUE;
|
||||||
|
ALTER TABLE sales ADD COLUMN recurly_invoice_number INTEGER;
|
||||||
|
|
||||||
|
ALTER TABLE sales ADD COLUMN recurly_subtotal_in_cents INTEGER;
|
||||||
|
ALTER TABLE sales ADD COLUMN recurly_tax_in_cents INTEGER;
|
||||||
|
ALTER TABLE sales ADD COLUMN recurly_total_in_cents INTEGER;
|
||||||
|
ALTER TABLE sales ADD COLUMN recurly_currency VARCHAR;
|
||||||
|
|
||||||
|
ALTER TABLE sale_line_items ADD COLUMN recurly_tax_in_cents INTEGER;
|
||||||
|
ALTER TABLE sale_line_items ADD COLUMN recurly_total_in_cents INTEGER;
|
||||||
|
ALTER TABLE sale_line_items ADD COLUMN recurly_currency VARCHAR;
|
||||||
|
ALTER TABLE sale_line_items ADD COLUMN recurly_discount_in_cents INTEGER;
|
||||||
|
|
||||||
|
ALTER TABLE sales ADD COLUMN sale_type VARCHAR NOT NULL;
|
||||||
|
|
||||||
|
ALTER TABLE recurly_transaction_web_hooks ALTER COLUMN subscription_id DROP NOT NULL;
|
||||||
|
|
||||||
|
CREATE INDEX recurly_transaction_web_hooks_invoice_id_ndx ON recurly_transaction_web_hooks(invoice_id);
|
||||||
|
|
||||||
|
ALTER TABLE jam_track_rights DROP COLUMN recurly_subscription_uuid;
|
||||||
|
|
@ -69,6 +69,7 @@ require "jam_ruby/connection_manager"
|
||||||
require "jam_ruby/version"
|
require "jam_ruby/version"
|
||||||
require "jam_ruby/environment"
|
require "jam_ruby/environment"
|
||||||
require "jam_ruby/init"
|
require "jam_ruby/init"
|
||||||
|
require "jam_ruby/app/mailers/admin_mailer"
|
||||||
require "jam_ruby/app/mailers/user_mailer"
|
require "jam_ruby/app/mailers/user_mailer"
|
||||||
require "jam_ruby/app/mailers/invited_user_mailer"
|
require "jam_ruby/app/mailers/invited_user_mailer"
|
||||||
require "jam_ruby/app/mailers/corp_mailer"
|
require "jam_ruby/app/mailers/corp_mailer"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
module JamRuby
|
||||||
|
# sends out a boring ale
|
||||||
|
class AdminMailer < ActionMailer::Base
|
||||||
|
include SendGrid
|
||||||
|
|
||||||
|
|
||||||
|
DEFAULT_SENDER = "JamKazam <noreply@jamkazam.com>"
|
||||||
|
|
||||||
|
default :from => DEFAULT_SENDER
|
||||||
|
|
||||||
|
sendgrid_category :use_subject_lines
|
||||||
|
#sendgrid_enable :opentrack, :clicktrack # this makes our emails creepy, imo (seth)
|
||||||
|
sendgrid_unique_args :env => Environment.mode
|
||||||
|
|
||||||
|
def alerts(options)
|
||||||
|
mail(to: APP_CONFIG.email_alerts_alias,
|
||||||
|
body: options[:body],
|
||||||
|
content_type: "text/plain",
|
||||||
|
subject: options[:subject])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -614,7 +614,8 @@ module JamRuby
|
||||||
def synchronize_recurly(jam_track)
|
def synchronize_recurly(jam_track)
|
||||||
begin
|
begin
|
||||||
recurly = RecurlyClient.new
|
recurly = RecurlyClient.new
|
||||||
recurly.create_jam_track_plan(jam_track) unless recurly.find_jam_track_plan(jam_track)
|
# no longer create JamTrack plans: VRFS-3028
|
||||||
|
# recurly.create_jam_track_plan(jam_track) unless recurly.find_jam_track_plan(jam_track)
|
||||||
rescue RecurlyClientError => x
|
rescue RecurlyClientError => x
|
||||||
finish('recurly_create_plan', x.errors.to_s)
|
finish('recurly_create_plan', x.errors.to_s)
|
||||||
return false
|
return false
|
||||||
|
|
|
||||||
|
|
@ -199,5 +199,6 @@ module JamRuby
|
||||||
def right_for_user(user)
|
def right_for_user(user)
|
||||||
jam_track_rights.where("user_id=?", user).first
|
jam_track_rights.where("user_id=?", user).first
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ module JamRuby
|
||||||
belongs_to :user, class_name: 'JamRuby::User'
|
belongs_to :user, class_name: 'JamRuby::User'
|
||||||
|
|
||||||
validates :recurly_transaction_id, presence: true
|
validates :recurly_transaction_id, presence: true
|
||||||
validates :subscription_id, presence: true
|
|
||||||
validates :action, presence: true
|
validates :action, presence: true
|
||||||
validates :status, presence: true
|
validates :status, presence: true
|
||||||
validates :amount_in_cents, numericality: {only_integer: true}
|
validates :amount_in_cents, numericality: {only_integer: true}
|
||||||
|
|
@ -68,8 +67,42 @@ module JamRuby
|
||||||
# now that we have the transaction saved, we also need to delete the jam_track_right if this is a refund, or voided
|
# now that we have the transaction saved, we also need to delete the jam_track_right if this is a refund, or voided
|
||||||
|
|
||||||
if transaction.transaction_type == 'refund' || transaction.transaction_type == 'void'
|
if transaction.transaction_type == 'refund' || transaction.transaction_type == 'void'
|
||||||
right = JamTrackRight.find_by_recurly_subscription_uuid(transaction.subscription_id)
|
sale = Sale.find_by_recurly_invoice_id(transaction.invoice_id)
|
||||||
right.destroy if right
|
|
||||||
|
if sale && sale.is_jam_track_sale?
|
||||||
|
if sale.sale_line_items.length == 1
|
||||||
|
if sale.recurly_total_in_cents == transaction.amount_in_cents
|
||||||
|
jam_track = sale.sale_line_items[0].product
|
||||||
|
jam_track_right = jam_track.right_for_user(transaction.user) if jam_track
|
||||||
|
if jam_track_right
|
||||||
|
jam_track_right.destroy
|
||||||
|
AdminMailer.alerts({
|
||||||
|
subject:"NOTICE: #{transaction.user.email} has had JamTrack: #{jam_track.name} revoked",
|
||||||
|
body: "A void event came from Recurly for sale with Recurly invoice ID #{sale.recurly_invoice_id}. We deleted their right to the track in our own database as a result."
|
||||||
|
}).deliver
|
||||||
|
else
|
||||||
|
AdminMailer.alerts({
|
||||||
|
subject:"NOTICE: #{transaction.user.email} got a refund, but unable to find JamTrackRight to delete",
|
||||||
|
body: "This should just mean the user already has no rights to the JamTrackRight when the refund came in. Not a big deal, but sort of weird..."
|
||||||
|
}).deliver
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
AdminMailer.alerts({
|
||||||
|
subject:"ACTION REQUIRED: #{transaction.user.email} got a refund it was not for total value of a JamTrack sale",
|
||||||
|
body: "We received a refund notice for an amount that was not the same as the original sale. So, no action was taken in the database. sale total: #{sale.recurly_total_in_cents}, refund amount: #{transaction.amount_in_cents}"
|
||||||
|
}).deliver
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
else
|
||||||
|
AdminMailer.alerts({
|
||||||
|
subject: "ACTION REQUIRED: #{transaction.user.email} has refund on invoice with multiple JamTracks",
|
||||||
|
body: "You will have to manually revoke any JamTrackRights in our database for the appropriate JamTracks"
|
||||||
|
}).deliver
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
transaction
|
transaction
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -3,30 +3,288 @@ module JamRuby
|
||||||
# a sale is created every time someone tries to buy something
|
# a sale is created every time someone tries to buy something
|
||||||
class Sale < ActiveRecord::Base
|
class Sale < ActiveRecord::Base
|
||||||
|
|
||||||
|
JAMTRACK_SALE = 'jamtrack'
|
||||||
|
|
||||||
belongs_to :user, class_name: 'JamRuby::User'
|
belongs_to :user, class_name: 'JamRuby::User'
|
||||||
has_many :sale_line_items, class_name: 'JamRuby::SaleLineItem'
|
has_many :sale_line_items, class_name: 'JamRuby::SaleLineItem'
|
||||||
|
|
||||||
validates :order_total, numericality: { only_integer: false }
|
validates :order_total, numericality: {only_integer: false}
|
||||||
validates :user, presence: true
|
validates :user, presence: true
|
||||||
|
|
||||||
def self.create(user)
|
|
||||||
|
def self.preview_invoice(current_user, shopping_carts)
|
||||||
|
|
||||||
|
line_items = {jam_tracks: []}
|
||||||
|
shopping_carts_jam_tracks = []
|
||||||
|
shopping_carts_subscriptions = []
|
||||||
|
shopping_carts.each do |shopping_cart|
|
||||||
|
|
||||||
|
if shopping_cart.is_jam_track?
|
||||||
|
shopping_carts_jam_tracks << shopping_cart
|
||||||
|
else
|
||||||
|
# XXX: this may have to be revisited when we actually have something other than JamTracks for puchase
|
||||||
|
shopping_carts_subscriptions << shopping_cart
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
jam_track_items = preview_invoice_jam_tracks(current_user, shopping_carts_jam_tracks)
|
||||||
|
line_items[:jam_tracks] = jam_track_items if jam_track_items
|
||||||
|
|
||||||
|
# TODO: process shopping_carts_subscriptions
|
||||||
|
|
||||||
|
line_items
|
||||||
|
end
|
||||||
|
|
||||||
|
# place_order will create one or more sales based on the contents of shopping_carts for the current user
|
||||||
|
# individual subscriptions will end up create their own sale (you can't have N subscriptions in one sale--recurly limitation)
|
||||||
|
# jamtracks however can be piled onto the same sale as adjustments (VRFS-3028)
|
||||||
|
# so this method may create 1 or more sales, , where 2 or more sales can occur if there are more than one subscriptions or subscription + jamtrack
|
||||||
|
def self.place_order(current_user, shopping_carts)
|
||||||
|
|
||||||
|
sales = []
|
||||||
|
shopping_carts_jam_tracks = []
|
||||||
|
shopping_carts_subscriptions = []
|
||||||
|
shopping_carts.each do |shopping_cart|
|
||||||
|
|
||||||
|
if shopping_cart.is_jam_track?
|
||||||
|
shopping_carts_jam_tracks << shopping_cart
|
||||||
|
else
|
||||||
|
# XXX: this may have to be revisited when we actually have something other than JamTracks for puchase
|
||||||
|
shopping_carts_subscriptions << shopping_cart
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
jam_track_sale = order_jam_tracks(current_user, shopping_carts_jam_tracks)
|
||||||
|
sales << jam_track_sale if jam_track_sale
|
||||||
|
|
||||||
|
# TODO: process shopping_carts_subscriptions
|
||||||
|
|
||||||
|
sales
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.preview_invoice_jam_tracks(current_user, shopping_carts_jam_tracks)
|
||||||
|
### XXX TODO;
|
||||||
|
|
||||||
|
# we currently use a fake plan in Recurly to estimate taxes using the Pricing.Attach metod in Recurly.js
|
||||||
|
|
||||||
|
# if we were to implement this the right way (ensure adjustments are on the account as necessary), then it would be better (more correct)
|
||||||
|
# just a pain to implement
|
||||||
|
end
|
||||||
|
|
||||||
|
# this method will either return a valid sale, or throw a RecurlyClientError or ActiveRecord validation error (save! failed)
|
||||||
|
# it may return an nil sale if the JamTrack(s) specified by the shopping carts are already owned
|
||||||
|
def self.order_jam_tracks(current_user, shopping_carts_jam_tracks)
|
||||||
|
|
||||||
|
client = RecurlyClient.new
|
||||||
|
|
||||||
|
sale = nil
|
||||||
|
Sale.transaction do
|
||||||
|
sale = create_jam_track_sale(current_user)
|
||||||
|
|
||||||
|
if sale.valid?
|
||||||
|
account = client.get_account(current_user)
|
||||||
|
if account.present?
|
||||||
|
|
||||||
|
purge_pending_adjustments(account)
|
||||||
|
|
||||||
|
created_adjustments = sale.process_jam_tracks(current_user, shopping_carts_jam_tracks, account)
|
||||||
|
|
||||||
|
# now invoice the sale ... almost done
|
||||||
|
|
||||||
|
begin
|
||||||
|
invoice = account.invoice!
|
||||||
|
sale.recurly_invoice_id = invoice.uuid
|
||||||
|
sale.recurly_invoice_number = invoice.invoice_number
|
||||||
|
|
||||||
|
# now slap in all the real tax/purchase totals
|
||||||
|
sale.recurly_subtotal_in_cents = invoice.subtotal_in_cents
|
||||||
|
sale.recurly_tax_in_cents = invoice.tax_in_cents
|
||||||
|
sale.recurly_total_in_cents = invoice.total_in_cents
|
||||||
|
sale.recurly_currency = invoice.currency
|
||||||
|
|
||||||
|
puts "Sale Line Items #{sale.sale_line_items.inspect}"
|
||||||
|
|
||||||
|
puts "----"
|
||||||
|
puts "Invoice Line Items #{invoice.line_items.inspect}"
|
||||||
|
# and resolve against sale_line_items
|
||||||
|
sale.sale_line_items.each do |sale_line_item|
|
||||||
|
found_line_item = false
|
||||||
|
invoice.line_items.each do |line_item|
|
||||||
|
if line_item.uuid == sale_line_item.recurly_adjustment_uuid
|
||||||
|
sale_line_item.recurly_tax_in_cents = line_item.tax_in_cents
|
||||||
|
sale_line_item.recurly_total_in_cents =line_item.total_in_cents
|
||||||
|
sale_line_item.recurly_currency = line_item.currency
|
||||||
|
sale_line_item.recurly_discount_in_cents = line_item.discount_in_cents
|
||||||
|
found_line_item = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
if !found_line_item
|
||||||
|
@@loge.error("can't find line item #{sale_line_item.recurly_adjustment_uuid}")
|
||||||
|
puts "CANT FIND LINE ITEM"
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
unless sale.save
|
||||||
|
raise RecurlyClientError, "Invalid sale (at end)."
|
||||||
|
end
|
||||||
|
rescue Recurly::Resource::Invalid => e
|
||||||
|
# this exception is thrown by invoice! if the invoice is invalid
|
||||||
|
sale.rollback_adjustments(current_user, created_adjustments)
|
||||||
|
sale = nil
|
||||||
|
raise ActiveRecord::Rollback # kill all db activity, but don't break outside logic
|
||||||
|
end
|
||||||
|
else
|
||||||
|
raise RecurlyClientError, "Could not find account to place order."
|
||||||
|
end
|
||||||
|
else
|
||||||
|
raise RecurlyClientError, "Invalid sale."
|
||||||
|
end
|
||||||
|
end
|
||||||
|
sale
|
||||||
|
end
|
||||||
|
|
||||||
|
def process_jam_tracks(current_user, shopping_carts_jam_tracks, account)
|
||||||
|
|
||||||
|
created_adjustments = []
|
||||||
|
|
||||||
|
begin
|
||||||
|
shopping_carts_jam_tracks.each do |shopping_cart|
|
||||||
|
process_jam_track(current_user, shopping_cart, account, created_adjustments)
|
||||||
|
end
|
||||||
|
rescue Recurly::Error, NoMethodError => x
|
||||||
|
# rollback any adjustments created if error
|
||||||
|
rollback_adjustments(user, created_adjustments)
|
||||||
|
raise RecurlyClientError, x.to_s
|
||||||
|
rescue Exception => e
|
||||||
|
# rollback any adjustments created if error
|
||||||
|
rollback_adjustments(user, created_adjustments)
|
||||||
|
raise e
|
||||||
|
end
|
||||||
|
|
||||||
|
created_adjustments
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def process_jam_track(current_user, shopping_cart, account, created_adjustments)
|
||||||
|
recurly_adjustment_uuid = nil
|
||||||
|
recurly_adjustment_credit_uuid = nil
|
||||||
|
|
||||||
|
# we do this because of ShoppingCart.remove_jam_track_from_cart; if it occurs, which should be rare, we need fresh shopping cart info
|
||||||
|
shopping_cart.reload
|
||||||
|
|
||||||
|
# get the JamTrack in this shopping cart
|
||||||
|
jam_track = shopping_cart.cart_product
|
||||||
|
|
||||||
|
if jam_track.right_for_user(current_user)
|
||||||
|
# if the user already owns the JamTrack, we should just skip this cart item, and destroy it
|
||||||
|
# if this occurs, we have to reload every shopping_cart as we iterate. so, we do at the top of the loop
|
||||||
|
ShoppingCart.remove_jam_track_from_cart(current_user, shopping_cart)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
# ask the shopping cart to create the correct Recurly adjustment attributes for a JamTrack
|
||||||
|
adjustments = shopping_cart.create_adjustment_attributes(current_user)
|
||||||
|
|
||||||
|
adjustments.each do |adjustment|
|
||||||
|
|
||||||
|
# create the adjustment at Recurly (this may not look like it, but it is a REST API)
|
||||||
|
created_adjustment = account.adjustments.new(adjustment)
|
||||||
|
created_adjustment.save
|
||||||
|
|
||||||
|
# if the adjustment could not be made, bail
|
||||||
|
raise RecurlyClientError.new(created_adjustment.errors) if created_adjustment.errors.any?
|
||||||
|
|
||||||
|
# keep track of adjustments we created for this order, in case we have to roll them back
|
||||||
|
created_adjustments << created_adjustment
|
||||||
|
|
||||||
|
if ShoppingCart.is_product_purchase?(adjustment)
|
||||||
|
# this was a normal product adjustment, so track it as such
|
||||||
|
recurly_adjustment_uuid = created_adjustment.uuid
|
||||||
|
else
|
||||||
|
# this was a 'credit' adjustment, so track it as such
|
||||||
|
recurly_adjustment_credit_uuid = created_adjustment.uuid
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# create one sale line item for every jam track
|
||||||
|
sale_line_item = SaleLineItem.create_from_shopping_cart(self, shopping_cart, nil, recurly_adjustment_uuid, recurly_adjustment_credit_uuid)
|
||||||
|
|
||||||
|
# if the sale line item is invalid, blow up the transaction
|
||||||
|
unless sale_line_item.valid?
|
||||||
|
@log.error("sale item invalid! #{sale_line_item.errors.inspect}")
|
||||||
|
puts("sale item invalid! #{sale_line_item.errors.inspect}")
|
||||||
|
Stats.write('web.recurly.purchase.sale_invalid', {message: sale_line_item.errors.to_s, value: 1})
|
||||||
|
raise RecurlyClientError.new(sale_line_item.errors)
|
||||||
|
end
|
||||||
|
|
||||||
|
# create a JamTrackRight (this needs to be in a transaction too to make sure we don't make these by accident)
|
||||||
|
jam_track_right = JamRuby::JamTrackRight.find_or_create_by_user_id_and_jam_track_id(current_user.id, jam_track.id) do |jam_track_right|
|
||||||
|
jam_track_right.redeemed = shopping_cart.free?
|
||||||
|
end
|
||||||
|
|
||||||
|
# also if the purchase was a free one, then update the user record to no longer allow redeemed jamtracks
|
||||||
|
User.where(id: current_user.id).update_all(has_redeemable_jamtrack: false) if shopping_cart.free?
|
||||||
|
|
||||||
|
# this can't go in the block above, as it's here to fix bad subscription UUIDs in an update path
|
||||||
|
if jam_track_right.recurly_adjustment_uuid != recurly_adjustment_uuid
|
||||||
|
jam_track_right.recurly_adjustment_uuid = recurly_adjustment_uuid
|
||||||
|
jam_track_right.recurly_adjustment_credit_uuid = recurly_adjustment_credit_uuid
|
||||||
|
unless jam_track_right.save
|
||||||
|
raise RecurlyClientError.new(jam_track_right.errors)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# delete the shopping cart; it's been dealt with
|
||||||
|
shopping_cart.destroy if shopping_cart
|
||||||
|
|
||||||
|
# blow up the transaction if the JamTrackRight did not get created
|
||||||
|
raise RecurlyClientError.new(jam_track_right.errors) if jam_track_right.errors.any?
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def rollback_adjustments(current_user, adjustments)
|
||||||
|
begin
|
||||||
|
adjustments.each { |adjustment| adjustment.destroy }
|
||||||
|
rescue Exception => e
|
||||||
|
AdminMailer.alerts({
|
||||||
|
subject: "ACTION REQUIRED: #{current_user.email} did not have all of his adjustments destroyed in rollback",
|
||||||
|
body: "go delete any adjustments on the account that don't belong. error: #{e}\n\nAdjustments: #{adjustments.inspect}"
|
||||||
|
}).deliver
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.purge_pending_adjustments(account)
|
||||||
|
account.adjustments.pending.find_each do |adjustment|
|
||||||
|
# we only pre-emptively destroy pending adjustments if they appear to be created by the server
|
||||||
|
adjustment.destroy if ShoppingCart.is_server_pending_adjustment?(adjustment)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def is_jam_track_sale?
|
||||||
|
sale_type == JAMTRACK_SALE
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.create_jam_track_sale(user)
|
||||||
sale = Sale.new
|
sale = Sale.new
|
||||||
sale.user = user
|
sale.user = user
|
||||||
|
sale.sale_type = JAMTRACK_SALE
|
||||||
sale.order_total = 0
|
sale.order_total = 0
|
||||||
sale.save
|
sale.save
|
||||||
sale
|
sale
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.check_integrity
|
# this checks just jamtrack sales appropriately
|
||||||
SaleLineItem.select([:total, :not_known, :succeeded, :failed, :refunded, :voided]).find_by_sql(
|
def self.check_integrity_of_jam_track_sales
|
||||||
"SELECT COUNT(sale_line_items.id) AS total,
|
Sale.select([:total, :voided]).find_by_sql(
|
||||||
COUNT(CASE WHEN transactions.id IS NULL THEN 1 ELSE null END) not_known,
|
"SELECT COUNT(sales.id) AS total,
|
||||||
COUNT(CASE WHEN transactions.transaction_type = '#{RecurlyTransactionWebHook::SUCCESSFUL_PAYMENT}' THEN 1 ELSE null END) succeeded,
|
|
||||||
COUNT(CASE WHEN transactions.transaction_type = '#{RecurlyTransactionWebHook::FAILED_PAYMENT}' THEN 1 ELSE null END) failed,
|
|
||||||
COUNT(CASE WHEN transactions.transaction_type = '#{RecurlyTransactionWebHook::REFUND}' THEN 1 ELSE null END) refunded,
|
|
||||||
COUNT(CASE WHEN transactions.transaction_type = '#{RecurlyTransactionWebHook::VOID}' THEN 1 ELSE null END) voided
|
COUNT(CASE WHEN transactions.transaction_type = '#{RecurlyTransactionWebHook::VOID}' THEN 1 ELSE null END) voided
|
||||||
FROM sale_line_items
|
FROM sales
|
||||||
LEFT OUTER JOIN recurly_transaction_web_hooks as transactions ON subscription_id = recurly_subscription_uuid")
|
LEFT OUTER JOIN recurly_transaction_web_hooks as transactions ON invoice_id = sales.recurly_invoice_id
|
||||||
|
WHERE sale_type = '#{JAMTRACK_SALE}'")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -18,10 +18,15 @@ module JamRuby
|
||||||
validates :recurly_plan_code, presence:true
|
validates :recurly_plan_code, presence:true
|
||||||
validates :sale, presence:true
|
validates :sale, presence:true
|
||||||
|
|
||||||
def self.create_from_shopping_cart(sale, shopping_cart, recurly_subscription_uuid)
|
def product
|
||||||
|
# TODO: beef up if there is more than one sort of sale
|
||||||
|
JamTrack.find(product_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.create_from_shopping_cart(sale, shopping_cart, recurly_subscription_uuid, recurly_adjustment_uuid, recurly_adjustment_credit_uuid)
|
||||||
product_info = shopping_cart.product_info
|
product_info = shopping_cart.product_info
|
||||||
|
|
||||||
sale.order_total = sale.order_total + product_info[:total_price]
|
sale.order_total = sale.order_total + product_info[:real_price]
|
||||||
|
|
||||||
sale_line_item = SaleLineItem.new
|
sale_line_item = SaleLineItem.new
|
||||||
sale_line_item.product_type = shopping_cart.cart_type
|
sale_line_item.product_type = shopping_cart.cart_type
|
||||||
|
|
@ -33,7 +38,9 @@ module JamRuby
|
||||||
sale_line_item.recurly_plan_code = product_info[:plan_code]
|
sale_line_item.recurly_plan_code = product_info[:plan_code]
|
||||||
sale_line_item.product_id = shopping_cart.cart_id
|
sale_line_item.product_id = shopping_cart.cart_id
|
||||||
sale_line_item.recurly_subscription_uuid = recurly_subscription_uuid
|
sale_line_item.recurly_subscription_uuid = recurly_subscription_uuid
|
||||||
sale_line_item.sale = sale
|
sale_line_item.recurly_adjustment_uuid = recurly_adjustment_uuid
|
||||||
|
sale_line_item.recurly_adjustment_credit_uuid = recurly_adjustment_credit_uuid
|
||||||
|
sale.sale_line_items << sale_line_item
|
||||||
sale_line_item.save
|
sale_line_item.save
|
||||||
sale_line_item
|
sale_line_item
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,19 @@
|
||||||
module JamRuby
|
module JamRuby
|
||||||
class ShoppingCart < ActiveRecord::Base
|
class ShoppingCart < ActiveRecord::Base
|
||||||
|
|
||||||
|
# just a normal purchase; used on the description field of a recurly adjustment
|
||||||
|
PURCHASE_NORMAL = 'purchase-normal'
|
||||||
|
# a free purchase; used on the description field of a recurly adjustment
|
||||||
|
PURCHASE_FREE = 'purchase-free'
|
||||||
|
# a techinicality of Recurly; we create a free-credit adjustment to balance out the free purchase adjustment
|
||||||
|
PURCHASE_FREE_CREDIT = 'purchase-free-credit'
|
||||||
|
|
||||||
|
PURCHASE_REASONS = [PURCHASE_NORMAL, PURCHASE_FREE, PURCHASE_FREE_CREDIT]
|
||||||
|
|
||||||
attr_accessible :quantity, :cart_type, :product_info
|
attr_accessible :quantity, :cart_type, :product_info
|
||||||
|
|
||||||
|
validates_uniqueness_of :cart_id, scope: :cart_type
|
||||||
|
|
||||||
belongs_to :user, :inverse_of => :shopping_carts, :class_name => "JamRuby::User", :foreign_key => "user_id"
|
belongs_to :user, :inverse_of => :shopping_carts, :class_name => "JamRuby::User", :foreign_key => "user_id"
|
||||||
|
|
||||||
validates :cart_id, presence: true
|
validates :cart_id, presence: true
|
||||||
|
|
@ -14,14 +25,20 @@ module JamRuby
|
||||||
|
|
||||||
def product_info
|
def product_info
|
||||||
product = self.cart_product
|
product = self.cart_product
|
||||||
{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?
|
{name: product.name, price: product.price, product_id: cart_id, plan_code: product.plan_code, real_price: real_price(product), total_price: total_price(product), quantity: quantity, marked_for_redeem: marked_for_redeem} unless product.nil?
|
||||||
|
end
|
||||||
|
|
||||||
|
# multiply quantity by price
|
||||||
|
def total_price(product)
|
||||||
|
quantity * product.price
|
||||||
end
|
end
|
||||||
|
|
||||||
# multiply (quantity - redeemable) by price
|
# multiply (quantity - redeemable) by price
|
||||||
def total_price(product)
|
def real_price(product)
|
||||||
(quantity - marked_for_redeem) * product.price
|
(quantity - marked_for_redeem) * product.price
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
def cart_product
|
def cart_product
|
||||||
self.cart_class_name.classify.constantize.find_by_id(self.cart_id) unless self.cart_class_name.blank?
|
self.cart_class_name.classify.constantize.find_by_id(self.cart_id) unless self.cart_class_name.blank?
|
||||||
end
|
end
|
||||||
|
|
@ -51,6 +68,59 @@ module JamRuby
|
||||||
cart
|
cart
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def is_jam_track?
|
||||||
|
cart_type == JamTrack::PRODUCT_TYPE
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# returns an array of adjustments for the shopping cart
|
||||||
|
def create_adjustment_attributes(current_user)
|
||||||
|
raise "not a jam track" unless is_jam_track?
|
||||||
|
|
||||||
|
info = self.product_info
|
||||||
|
|
||||||
|
if free?
|
||||||
|
|
||||||
|
# create the credit, then the pseudo charge
|
||||||
|
[
|
||||||
|
{
|
||||||
|
accounting_code: PURCHASE_FREE_CREDIT,
|
||||||
|
currency: 'USD',
|
||||||
|
unit_amount_in_cents: -(info[:total_price] * 100).to_i,
|
||||||
|
description: "JamTrack: " + info[:name] + " (Credit)",
|
||||||
|
tax_exempt: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accounting_code: PURCHASE_FREE,
|
||||||
|
currency: 'USD',
|
||||||
|
unit_amount_in_cents: (info[:total_price] * 100).to_i,
|
||||||
|
description: "JamTrack: " + info[:name],
|
||||||
|
tax_exempt: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
else
|
||||||
|
[
|
||||||
|
{
|
||||||
|
accounting_code: PURCHASE_NORMAL,
|
||||||
|
currency: 'USD',
|
||||||
|
unit_amount_in_cents: (info[:total_price] * 100).to_i,
|
||||||
|
description: "JamTrack: " + info[:name],
|
||||||
|
tax_exempt: false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.is_product_purchase?(adjustment)
|
||||||
|
(adjustment[:accounting_code].include?(PURCHASE_FREE) || adjustment[:accounting_code].include?(PURCHASE_NORMAL)) && !adjustment[:accounting_code].include?(PURCHASE_FREE_CREDIT)
|
||||||
|
end
|
||||||
|
|
||||||
|
# recurly_adjustment is a Recurly::Adjustment (http://www.rubydoc.info/gems/recurly/Recurly/Adjustment)
|
||||||
|
# this asks, 'is this a pending adjustment?' AND 'was this adjustment created by the server (vs manually by someone -- we should leave those alone).'
|
||||||
|
def self.is_server_pending_adjustment?(recurly_adjustment)
|
||||||
|
recurly_adjustment.state == 'pending' && (recurly_adjustment.accounting_code.include?(PURCHASE_FREE) || recurly_adjustment.accounting_code.include?(PURCHASE_NORMAL) || recurly_adjustment.accounting_code.include?(PURCHASE_FREE_CREDIT))
|
||||||
|
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 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
|
# if no shpping carts have been marked, then mark it redeemable
|
||||||
# should be wrapped in a TRANSACTION
|
# should be wrapped in a TRANSACTION
|
||||||
|
|
@ -73,20 +143,8 @@ module JamRuby
|
||||||
def self.add_jam_track_to_cart(any_user, jam_track)
|
def self.add_jam_track_to_cart(any_user, jam_track)
|
||||||
cart = nil
|
cart = nil
|
||||||
ShoppingCart.transaction do
|
ShoppingCart.transaction do
|
||||||
# does this user already have this JamTrack in their cart? If so, don't add it.
|
mark_redeem = ShoppingCart.user_has_redeemable_jam_track?(any_user)
|
||||||
|
cart = ShoppingCart.create(any_user, jam_track, 1, mark_redeem)
|
||||||
duplicate_found = false
|
|
||||||
any_user.shopping_carts.each do |shopping_cart|
|
|
||||||
if shopping_cart.cart_type == JamTrack::PRODUCT_TYPE && shopping_cart.cart_id == jam_track.id
|
|
||||||
duplicate_found = true
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
unless duplicate_found
|
|
||||||
mark_redeem = ShoppingCart.user_has_redeemable_jam_track?(any_user)
|
|
||||||
cart = ShoppingCart.create(any_user, jam_track, 1, mark_redeem)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
cart
|
cart
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
require 'recurly'
|
require 'recurly'
|
||||||
module JamRuby
|
module JamRuby
|
||||||
class RecurlyClient
|
class RecurlyClient
|
||||||
def initialize()
|
def initialize()
|
||||||
@log = Logging.logger[self]
|
@log = Logging.logger[self]
|
||||||
end
|
end
|
||||||
|
|
@ -11,37 +11,37 @@ module JamRuby
|
||||||
begin
|
begin
|
||||||
#puts "Recurly.api_key: #{Recurly.api_key}"
|
#puts "Recurly.api_key: #{Recurly.api_key}"
|
||||||
account = Recurly::Account.create(options)
|
account = Recurly::Account.create(options)
|
||||||
raise RecurlyClientError.new(account.errors) if account.errors.any?
|
raise RecurlyClientError.new(account.errors) if account.errors.any?
|
||||||
rescue Recurly::Error, NoMethodError => x
|
rescue Recurly::Error, NoMethodError => x
|
||||||
#puts "Error: #{x} : #{Kernel.caller}"
|
#puts "Error: #{x} : #{Kernel.caller}"
|
||||||
raise RecurlyClientError, x.to_s
|
raise RecurlyClientError, x.to_s
|
||||||
else
|
else
|
||||||
if account
|
if account
|
||||||
current_user.update_attribute(:recurly_code, account.account_code)
|
current_user.update_attribute(:recurly_code, account.account_code)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
account
|
account
|
||||||
end
|
end
|
||||||
|
|
||||||
def has_account?(current_user)
|
def has_account?(current_user)
|
||||||
account = get_account(current_user)
|
account = get_account(current_user)
|
||||||
!!account
|
!!account
|
||||||
end
|
end
|
||||||
|
|
||||||
def delete_account(current_user)
|
def delete_account(current_user)
|
||||||
account = get_account(current_user)
|
account = get_account(current_user)
|
||||||
if (account)
|
if (account)
|
||||||
begin
|
begin
|
||||||
account.destroy
|
account.destroy
|
||||||
rescue Recurly::Error, NoMethodError => x
|
rescue Recurly::Error, NoMethodError => x
|
||||||
raise RecurlyClientError, x.to_s
|
raise RecurlyClientError, x.to_s
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
raise RecurlyClientError, "Could not find account to delete."
|
raise RecurlyClientError, "Could not find account to delete."
|
||||||
end
|
end
|
||||||
account
|
account
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_account(current_user)
|
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
|
||||||
rescue Recurly::Error => x
|
rescue Recurly::Error => x
|
||||||
|
|
@ -51,9 +51,9 @@ module JamRuby
|
||||||
def update_account(current_user, billing_info=nil)
|
def update_account(current_user, billing_info=nil)
|
||||||
account = get_account(current_user)
|
account = get_account(current_user)
|
||||||
if(account.present?)
|
if(account.present?)
|
||||||
options = account_hash(current_user, billing_info)
|
options = account_hash(current_user, billing_info)
|
||||||
begin
|
begin
|
||||||
account.update_attributes(options)
|
account.update_attributes(options)
|
||||||
rescue Recurly::Error, NoMethodError => x
|
rescue Recurly::Error, NoMethodError => x
|
||||||
raise RecurlyClientError, x.to_s
|
raise RecurlyClientError, x.to_s
|
||||||
end
|
end
|
||||||
|
|
@ -95,7 +95,7 @@ module JamRuby
|
||||||
raise RecurlyClientError, x.to_s
|
raise RecurlyClientError, x.to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
raise RecurlyClientError.new(account.errors) if account.errors.any?
|
raise RecurlyClientError.new(account.errors) if account.errors.any?
|
||||||
else
|
else
|
||||||
raise RecurlyClientError, "Could not find account to update billing info."
|
raise RecurlyClientError, "Could not find account to update billing info."
|
||||||
end
|
end
|
||||||
|
|
@ -121,21 +121,21 @@ module JamRuby
|
||||||
#puts "subscription.plan.plan_code: #{subscription.plan.plan_code} / #{jam_track.plan_code} / #{subscription.plan.plan_code == jam_track.plan_code}"
|
#puts "subscription.plan.plan_code: #{subscription.plan.plan_code} / #{jam_track.plan_code} / #{subscription.plan.plan_code == jam_track.plan_code}"
|
||||||
if(subscription.plan.plan_code == jam_track.plan_code)
|
if(subscription.plan.plan_code == jam_track.plan_code)
|
||||||
subscription.terminate(:full)
|
subscription.terminate(:full)
|
||||||
raise RecurlyClientError.new(subscription.errors) if subscription.errors.any?
|
raise RecurlyClientError.new(subscription.errors) if subscription.errors.any?
|
||||||
terminated = true
|
terminated = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if terminated
|
if terminated
|
||||||
jam_track_right.destroy()
|
jam_track_right.destroy()
|
||||||
else
|
else
|
||||||
raise RecurlyClientError, "Subscription '#{jam_track.plan_code}' not found for this user; could not issue refund."
|
raise RecurlyClientError, "Subscription '#{jam_track.plan_code}' not found for this user; could not issue refund."
|
||||||
end
|
end
|
||||||
|
|
||||||
rescue Recurly::Error, NoMethodError => x
|
rescue Recurly::Error, NoMethodError => x
|
||||||
raise RecurlyClientError, x.to_s
|
raise RecurlyClientError, x.to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
else
|
else
|
||||||
raise RecurlyClientError, "Could not find account to refund order."
|
raise RecurlyClientError, "Could not find account to refund order."
|
||||||
end
|
end
|
||||||
|
|
@ -177,89 +177,18 @@ module JamRuby
|
||||||
raise RecurlyClientError.new(plan.errors) if plan.errors.any?
|
raise RecurlyClientError.new(plan.errors) if plan.errors.any?
|
||||||
end
|
end
|
||||||
|
|
||||||
def place_order(current_user, jam_track, shopping_cart, sale)
|
|
||||||
jam_track_right = nil
|
|
||||||
account = get_account(current_user)
|
|
||||||
if (account.present?)
|
|
||||||
begin
|
|
||||||
|
|
||||||
# see if we can find existing plan for this plan_code, which should occur for previous-in-time error scenarios
|
|
||||||
recurly_subscription_uuid = nil
|
|
||||||
account.subscriptions.find_each do |subscription|
|
|
||||||
if subscription.plan.plan_code == jam_track.plan_code
|
|
||||||
recurly_subscription_uuid = subscription.uuid
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
free = false
|
|
||||||
|
|
||||||
# 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
|
|
||||||
|
|
||||||
# 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?
|
|
||||||
|
|
||||||
# add a line item for the sale
|
|
||||||
sale_line_item = SaleLineItem.create_from_shopping_cart(sale, shopping_cart, subscription.uuid)
|
|
||||||
|
|
||||||
unless sale_line_item.valid?
|
|
||||||
@log.error("sale item invalid! #{sale_line_item.errors.inspect}")
|
|
||||||
puts("sale item invalid! #{sale_line_item.errors.inspect}")
|
|
||||||
Stats.write('web.recurly.purchase.sale_invalid', {message: sale.errors.to_s, value:1})
|
|
||||||
end
|
|
||||||
|
|
||||||
# delete from shopping cart the subscription
|
|
||||||
shopping_cart.destroy if shopping_cart
|
|
||||||
|
|
||||||
recurly_subscription_uuid = subscription.uuid
|
|
||||||
end
|
|
||||||
|
|
||||||
#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) do |jam_track_right|
|
|
||||||
jam_track_right.redeemed = free
|
|
||||||
end
|
|
||||||
|
|
||||||
# also if the purchase was a free one, then update the user record to no longer allow redeemed jamtracks
|
|
||||||
User.where(id: current_user.id).update_all(has_redeemable_jamtrack: false) if free
|
|
||||||
|
|
||||||
# this can't go in the block above, as it's here to fix bad subscription UUIDs in an update path
|
|
||||||
if jam_track_right.recurly_subscription_uuid != recurly_subscription_uuid
|
|
||||||
jam_track_right.recurly_subscription_uuid = recurly_subscription_uuid
|
|
||||||
jam_track_right.save
|
|
||||||
end
|
|
||||||
|
|
||||||
raise RecurlyClientError.new("Error creating jam_track_right for jam_track: #{jam_track.id}") if jam_track_right.nil?
|
|
||||||
raise RecurlyClientError.new(jam_track_right.errors) if jam_track_right.errors.any?
|
|
||||||
rescue Recurly::Error, NoMethodError => x
|
|
||||||
raise RecurlyClientError, x.to_s
|
|
||||||
end
|
|
||||||
|
|
||||||
raise RecurlyClientError.new(account.errors) if account.errors.any?
|
|
||||||
else
|
|
||||||
raise RecurlyClientError, "Could not find account to place order."
|
|
||||||
end
|
|
||||||
jam_track_right
|
|
||||||
end
|
|
||||||
|
|
||||||
def find_or_create_account(current_user, billing_info)
|
def find_or_create_account(current_user, billing_info)
|
||||||
account = get_account(current_user)
|
account = get_account(current_user)
|
||||||
|
|
||||||
if(account.nil?)
|
if(account.nil?)
|
||||||
account = create_account(current_user, billing_info)
|
account = create_account(current_user, billing_info)
|
||||||
else
|
else
|
||||||
update_billing_info(current_user, billing_info)
|
update_billing_info(current_user, billing_info)
|
||||||
end
|
end
|
||||||
account
|
account
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
private
|
private
|
||||||
def account_hash(current_user, billing_info)
|
def account_hash(current_user, billing_info)
|
||||||
options = {
|
options = {
|
||||||
|
|
@ -273,7 +202,7 @@ module JamRuby
|
||||||
country: current_user.country
|
country: current_user.country
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
options[:billing_info] = billing_info if billing_info
|
options[:billing_info] = billing_info if billing_info
|
||||||
options
|
options
|
||||||
end
|
end
|
||||||
|
|
@ -282,11 +211,11 @@ module JamRuby
|
||||||
class RecurlyClientError < Exception
|
class RecurlyClientError < Exception
|
||||||
attr_accessor :errors
|
attr_accessor :errors
|
||||||
def initialize(data)
|
def initialize(data)
|
||||||
if data.respond_to?('has_key?')
|
if data.respond_to?('has_key?')
|
||||||
self.errors = data
|
self.errors = data
|
||||||
else
|
else
|
||||||
self.errors = {:message=>data.to_s}
|
self.errors = {:message=>data.to_s}
|
||||||
end
|
end
|
||||||
end # initialize
|
end # initialize
|
||||||
|
|
||||||
def to_s
|
def to_s
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ require 'spec_helper'
|
||||||
|
|
||||||
describe RecurlyTransactionWebHook do
|
describe RecurlyTransactionWebHook do
|
||||||
|
|
||||||
|
|
||||||
let(:refund_xml) {'<?xml version="1.0" encoding="UTF-8"?>
|
let(:refund_xml) {'<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<successful_refund_notification>
|
<successful_refund_notification>
|
||||||
<account>
|
<account>
|
||||||
|
|
@ -120,8 +121,15 @@ describe RecurlyTransactionWebHook do
|
||||||
|
|
||||||
it "deletes jam_track_right when refunded" do
|
it "deletes jam_track_right when refunded" do
|
||||||
|
|
||||||
|
sale = Sale.create_jam_track_sale(@user)
|
||||||
|
sale.recurly_invoice_id = '2da71ad9c657adf9fe618e4f058c78bb'
|
||||||
|
sale.recurly_total_in_cents = 216
|
||||||
|
sale.save!
|
||||||
# create a jam_track right, which should be whacked as soon as we craete the web hook
|
# create a jam_track right, which should be whacked as soon as we craete the web hook
|
||||||
jam_track_right = FactoryGirl.create(:jam_track_right, user: @user, recurly_subscription_uuid: '2da71ad97c826a7b784c264ac59c04de')
|
jam_track_right = FactoryGirl.create(:jam_track_right, user: @user, recurly_adjustment_uuid: 'bleh')
|
||||||
|
|
||||||
|
shopping_cart = ShoppingCart.create(@user, jam_track_right.jam_track)
|
||||||
|
SaleLineItem.create_from_shopping_cart(sale, shopping_cart, nil, '2da71ad9c657adf9fe618e4f058c78bb', nil)
|
||||||
|
|
||||||
document = Nokogiri::XML(refund_xml)
|
document = Nokogiri::XML(refund_xml)
|
||||||
|
|
||||||
|
|
@ -131,8 +139,16 @@ describe RecurlyTransactionWebHook do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "deletes jam_track_right when voided" do
|
it "deletes jam_track_right when voided" do
|
||||||
|
|
||||||
|
sale = Sale.create_jam_track_sale(@user)
|
||||||
|
sale.recurly_invoice_id = '2da71ad9c657adf9fe618e4f058c78bb'
|
||||||
|
sale.recurly_total_in_cents = 216
|
||||||
|
sale.save!
|
||||||
# create a jam_track right, which should be whacked as soon as we craete the web hook
|
# create a jam_track right, which should be whacked as soon as we craete the web hook
|
||||||
jam_track_right = FactoryGirl.create(:jam_track_right, user: @user, recurly_subscription_uuid: '2da71ad97c826a7b784c264ac59c04de')
|
jam_track_right = FactoryGirl.create(:jam_track_right, user: @user, recurly_adjustment_uuid: 'blah')
|
||||||
|
|
||||||
|
shopping_cart = ShoppingCart.create(@user, jam_track_right.jam_track)
|
||||||
|
SaleLineItem.create_from_shopping_cart(sale, shopping_cart, nil, '2da71ad9c657adf9fe618e4f058c78bb', nil)
|
||||||
|
|
||||||
document = Nokogiri::XML(void_xml)
|
document = Nokogiri::XML(void_xml)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,72 +1,289 @@
|
||||||
|
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
describe Sale do
|
describe Sale do
|
||||||
|
|
||||||
describe "check_integrity" do
|
|
||||||
|
describe "place_order" do
|
||||||
|
|
||||||
let(:user) {FactoryGirl.create(:user)}
|
let(:user) {FactoryGirl.create(:user)}
|
||||||
let(:jam_track) {FactoryGirl.create(:jam_track)}
|
let(:jamtrack) { FactoryGirl.create(:jam_track) }
|
||||||
|
let(:jam_track_price_in_cents) { (jamtrack.price * 100).to_i }
|
||||||
|
let(:client) { RecurlyClient.new }
|
||||||
|
let(:billing_info) {
|
||||||
|
info = {}
|
||||||
|
info[:first_name] = user.first_name
|
||||||
|
info[:last_name] = user.last_name
|
||||||
|
info[:address1] = 'Test Address 1'
|
||||||
|
info[:address2] = 'Test Address 2'
|
||||||
|
info[:city] = user.city
|
||||||
|
info[:state] = user.state
|
||||||
|
info[:country] = user.country
|
||||||
|
info[:zip] = '12345'
|
||||||
|
info[:number] = '4111-1111-1111-1111'
|
||||||
|
info[:month] = '08'
|
||||||
|
info[:year] = '2017'
|
||||||
|
info[:verification_value] = '111'
|
||||||
|
info
|
||||||
|
}
|
||||||
|
|
||||||
|
after(:each) do
|
||||||
|
if user.recurly_code
|
||||||
|
account = Recurly::Account.find(user.recurly_code)
|
||||||
|
if account.present?
|
||||||
|
account.destroy
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
it "for a free jam track" do
|
||||||
|
shopping_cart = ShoppingCart.create user, jamtrack, 1, true
|
||||||
|
client.find_or_create_account(user, billing_info)
|
||||||
|
|
||||||
|
sales = Sale.place_order(user, [shopping_cart])
|
||||||
|
|
||||||
|
user.reload
|
||||||
|
user.sales.length.should eq(1)
|
||||||
|
|
||||||
|
sales.should eq(user.sales)
|
||||||
|
sale = sales[0]
|
||||||
|
sale.recurly_invoice_id.should_not be_nil
|
||||||
|
|
||||||
|
sale.recurly_subtotal_in_cents.should eq(jam_track_price_in_cents)
|
||||||
|
sale.recurly_tax_in_cents.should eq(0)
|
||||||
|
sale.recurly_total_in_cents.should eq(0)
|
||||||
|
sale.recurly_currency.should eq('USD')
|
||||||
|
sale.order_total.should eq(0)
|
||||||
|
sale.sale_line_items.length.should == 1
|
||||||
|
sale_line_item = sale.sale_line_items[0]
|
||||||
|
sale_line_item.recurly_tax_in_cents.should eq(0)
|
||||||
|
sale_line_item.recurly_total_in_cents.should eq(jam_track_price_in_cents)
|
||||||
|
sale_line_item.recurly_currency.should eq('USD')
|
||||||
|
sale_line_item.recurly_discount_in_cents.should eq(0)
|
||||||
|
sale_line_item.product_type.should eq(JamTrack::PRODUCT_TYPE)
|
||||||
|
sale_line_item.unit_price.should eq(jamtrack.price)
|
||||||
|
sale_line_item.quantity.should eq(1)
|
||||||
|
sale_line_item.free.should eq(1)
|
||||||
|
sale_line_item.sales_tax.should be_nil
|
||||||
|
sale_line_item.shipping_handling.should eq(0)
|
||||||
|
sale_line_item.recurly_plan_code.should eq(jamtrack.plan_code)
|
||||||
|
sale_line_item.product_id.should eq(jamtrack.id)
|
||||||
|
sale_line_item.recurly_subscription_uuid.should be_nil
|
||||||
|
sale_line_item.recurly_adjustment_uuid.should_not be_nil
|
||||||
|
sale_line_item.recurly_adjustment_credit_uuid.should_not be_nil
|
||||||
|
sale_line_item.recurly_adjustment_uuid.should eq(user.jam_track_rights.last.recurly_adjustment_uuid)
|
||||||
|
sale_line_item.recurly_adjustment_credit_uuid.should eq(user.jam_track_rights.last.recurly_adjustment_credit_uuid)
|
||||||
|
|
||||||
|
# verify subscription is in Recurly
|
||||||
|
recurly_account = client.get_account(user)
|
||||||
|
adjustments = recurly_account.adjustments
|
||||||
|
adjustments.should_not be_nil
|
||||||
|
adjustments.should have(2).items
|
||||||
|
free_purchase= adjustments[0]
|
||||||
|
free_purchase.unit_amount_in_cents.should eq((jamtrack.price * 100).to_i)
|
||||||
|
free_purchase.accounting_code.should eq(ShoppingCart::PURCHASE_FREE)
|
||||||
|
free_purchase.description.should eq("JamTrack: " + jamtrack.name)
|
||||||
|
free_purchase.state.should eq('invoiced')
|
||||||
|
free_purchase.uuid.should eq(sale_line_item.recurly_adjustment_uuid)
|
||||||
|
|
||||||
|
free_credit = adjustments[1]
|
||||||
|
free_credit.unit_amount_in_cents.should eq(-(jamtrack.price * 100).to_i)
|
||||||
|
free_credit.accounting_code.should eq(ShoppingCart::PURCHASE_FREE_CREDIT)
|
||||||
|
free_credit.description.should eq("JamTrack: " + jamtrack.name + " (Credit)")
|
||||||
|
free_credit.state.should eq('invoiced')
|
||||||
|
free_credit.uuid.should eq(sale_line_item.recurly_adjustment_credit_uuid)
|
||||||
|
|
||||||
|
invoices = recurly_account.invoices
|
||||||
|
invoices.should have(1).items
|
||||||
|
invoice = invoices[0]
|
||||||
|
invoice.uuid.should eq(sale.recurly_invoice_id)
|
||||||
|
invoice.line_items.should have(2).items # should have both adjustments associated
|
||||||
|
invoice.line_items[0].should eq(free_credit)
|
||||||
|
invoice.line_items[1].should eq(free_purchase)
|
||||||
|
invoice.subtotal_in_cents.should eq((jamtrack.price * 100).to_i)
|
||||||
|
invoice.total_in_cents.should eq(0)
|
||||||
|
invoice.state.should eq('collected')
|
||||||
|
|
||||||
|
# verify jam_track_rights data
|
||||||
|
user.jam_track_rights.should_not be_nil
|
||||||
|
user.jam_track_rights.should have(1).items
|
||||||
|
user.jam_track_rights.last.jam_track.id.should eq(jamtrack.id)
|
||||||
|
user.jam_track_rights.last.redeemed.should be_true
|
||||||
|
user.has_redeemable_jamtrack.should be_false
|
||||||
|
end
|
||||||
|
|
||||||
|
it "for a normally priced jam track" do
|
||||||
|
user.has_redeemable_jamtrack = false
|
||||||
|
user.save!
|
||||||
|
shopping_cart = ShoppingCart.create user, jamtrack, 1, false
|
||||||
|
client.find_or_create_account(user, billing_info)
|
||||||
|
|
||||||
|
sales = Sale.place_order(user, [shopping_cart])
|
||||||
|
|
||||||
|
user.reload
|
||||||
|
user.sales.length.should eq(1)
|
||||||
|
|
||||||
|
sales.should eq(user.sales)
|
||||||
|
sale = sales[0]
|
||||||
|
sale.recurly_invoice_id.should_not be_nil
|
||||||
|
|
||||||
|
sale.recurly_subtotal_in_cents.should eq(jam_track_price_in_cents)
|
||||||
|
sale.recurly_tax_in_cents.should eq(0)
|
||||||
|
sale.recurly_total_in_cents.should eq(jam_track_price_in_cents)
|
||||||
|
sale.recurly_currency.should eq('USD')
|
||||||
|
|
||||||
|
sale.order_total.should eq(jamtrack.price)
|
||||||
|
sale.sale_line_items.length.should == 1
|
||||||
|
sale_line_item = sale.sale_line_items[0]
|
||||||
|
# validate we are storing pricing info from recurly
|
||||||
|
sale_line_item.recurly_tax_in_cents.should eq(0)
|
||||||
|
sale_line_item.recurly_total_in_cents.should eq(jam_track_price_in_cents)
|
||||||
|
sale_line_item.recurly_currency.should eq('USD')
|
||||||
|
sale_line_item.recurly_discount_in_cents.should eq(0)
|
||||||
|
sale_line_item.product_type.should eq(JamTrack::PRODUCT_TYPE)
|
||||||
|
sale_line_item.unit_price.should eq(jamtrack.price)
|
||||||
|
sale_line_item.quantity.should eq(1)
|
||||||
|
sale_line_item.free.should eq(0)
|
||||||
|
sale_line_item.sales_tax.should be_nil
|
||||||
|
sale_line_item.shipping_handling.should eq(0)
|
||||||
|
sale_line_item.recurly_plan_code.should eq(jamtrack.plan_code)
|
||||||
|
sale_line_item.product_id.should eq(jamtrack.id)
|
||||||
|
sale_line_item.recurly_subscription_uuid.should be_nil
|
||||||
|
sale_line_item.recurly_adjustment_uuid.should_not be_nil
|
||||||
|
sale_line_item.recurly_adjustment_credit_uuid.should be_nil
|
||||||
|
sale_line_item.recurly_adjustment_uuid.should eq(user.jam_track_rights.last.recurly_adjustment_uuid)
|
||||||
|
|
||||||
|
# verify subscription is in Recurly
|
||||||
|
recurly_account = client.get_account(user)
|
||||||
|
adjustments = recurly_account.adjustments
|
||||||
|
adjustments.should_not be_nil
|
||||||
|
adjustments.should have(1).items
|
||||||
|
purchase= adjustments[0]
|
||||||
|
purchase.unit_amount_in_cents.should eq((jamtrack.price * 100).to_i)
|
||||||
|
purchase.accounting_code.should eq(ShoppingCart::PURCHASE_NORMAL)
|
||||||
|
purchase.description.should eq("JamTrack: " + jamtrack.name)
|
||||||
|
purchase.state.should eq('invoiced')
|
||||||
|
purchase.uuid.should eq(sale_line_item.recurly_adjustment_uuid)
|
||||||
|
|
||||||
|
invoices = recurly_account.invoices
|
||||||
|
invoices.should have(1).items
|
||||||
|
invoice = invoices[0]
|
||||||
|
invoice.uuid.should eq(sale.recurly_invoice_id)
|
||||||
|
invoice.line_items.should have(1).items # should have single adjustment associated
|
||||||
|
invoice.line_items[0].should eq(purchase)
|
||||||
|
invoice.subtotal_in_cents.should eq((jamtrack.price * 100).to_i)
|
||||||
|
invoice.total_in_cents.should eq((jamtrack.price * 100).to_i)
|
||||||
|
invoice.state.should eq('collected')
|
||||||
|
|
||||||
|
# verify jam_track_rights data
|
||||||
|
user.jam_track_rights.should_not be_nil
|
||||||
|
user.jam_track_rights.should have(1).items
|
||||||
|
user.jam_track_rights.last.jam_track.id.should eq(jamtrack.id)
|
||||||
|
user.jam_track_rights.last.redeemed.should be_false
|
||||||
|
user.has_redeemable_jamtrack.should be_false
|
||||||
|
end
|
||||||
|
|
||||||
|
it "for a jamtrack already owned" do
|
||||||
|
shopping_cart = ShoppingCart.create user, jamtrack, 1, true
|
||||||
|
client.find_or_create_account(user, billing_info)
|
||||||
|
|
||||||
|
sales = Sale.place_order(user, [shopping_cart])
|
||||||
|
|
||||||
|
user.reload
|
||||||
|
user.sales.length.should eq(1)
|
||||||
|
|
||||||
|
shopping_cart = ShoppingCart.create user, jamtrack, 1, false
|
||||||
|
sales = Sale.place_order(user, [shopping_cart])
|
||||||
|
sales.should have(0).items
|
||||||
|
# also, verify that no earlier adjustments were affected
|
||||||
|
recurly_account = client.get_account(user)
|
||||||
|
adjustments = recurly_account.adjustments
|
||||||
|
adjustments.should have(2).items
|
||||||
|
end
|
||||||
|
|
||||||
|
# this test counts on the fact that two adjustments are made when buying a free JamTrack
|
||||||
|
# so if we make the second adjustment invalid from Recurly's standpoint, then
|
||||||
|
# we can see if the first one is ultimately destroyed
|
||||||
|
it "rolls back created adjustments if error" do
|
||||||
|
|
||||||
|
shopping_cart = ShoppingCart.create user, jamtrack, 1, true
|
||||||
|
|
||||||
|
# grab the real response; we will modify it to make a nil accounting code
|
||||||
|
adjustment_attrs = shopping_cart.create_adjustment_attributes(user)
|
||||||
|
client.find_or_create_account(user, billing_info)
|
||||||
|
|
||||||
|
adjustment_attrs[1][:unit_amount_in_cents] = nil # invalid amount
|
||||||
|
ShoppingCart.any_instance.stub(:create_adjustment_attributes).and_return(adjustment_attrs)
|
||||||
|
|
||||||
|
expect { Sale.place_order(user, [shopping_cart]) }.to raise_error(JamRuby::RecurlyClientError)
|
||||||
|
|
||||||
|
user.reload
|
||||||
|
user.sales.should have(0).items
|
||||||
|
|
||||||
|
recurly_account = client.get_account(user)
|
||||||
|
recurly_account.adjustments.should have(0).items
|
||||||
|
end
|
||||||
|
|
||||||
|
it "rolls back adjustments created before the order" do
|
||||||
|
shopping_cart = ShoppingCart.create user, jamtrack, 1, true
|
||||||
|
client.find_or_create_account(user, billing_info)
|
||||||
|
|
||||||
|
# create a single adjustment on the account
|
||||||
|
adjustment_attrs = shopping_cart.create_adjustment_attributes(user)
|
||||||
|
recurly_account = client.get_account(user)
|
||||||
|
adjustment = recurly_account.adjustments.new (adjustment_attrs[0])
|
||||||
|
adjustment.save
|
||||||
|
adjustment.errors.any?.should be_false
|
||||||
|
|
||||||
|
sales = Sale.place_order(user, [shopping_cart])
|
||||||
|
|
||||||
|
user.reload
|
||||||
|
|
||||||
|
recurly_account = client.get_account(user)
|
||||||
|
adjustments = recurly_account.adjustments
|
||||||
|
adjustments.should have(2).items # two adjustments are created for a free jamtrack; that should be all there is
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "check_integrity_of_jam_track_sales" do
|
||||||
|
|
||||||
|
let(:user) { FactoryGirl.create(:user) }
|
||||||
|
let(:jam_track) { FactoryGirl.create(:jam_track) }
|
||||||
|
|
||||||
it "empty" do
|
it "empty" do
|
||||||
check_integrity = Sale.check_integrity
|
check_integrity = Sale.check_integrity_of_jam_track_sales
|
||||||
check_integrity.length.should eq(1)
|
check_integrity.length.should eq(1)
|
||||||
r = check_integrity[0]
|
r = check_integrity[0]
|
||||||
r.total.to_i.should eq(0)
|
r.total.to_i.should eq(0)
|
||||||
r.not_known.to_i.should eq(0)
|
|
||||||
r.succeeded.to_i.should eq(0)
|
|
||||||
r.failed.to_i.should eq(0)
|
|
||||||
r.refunded.to_i.should eq(0)
|
|
||||||
r.voided.to_i.should eq(0)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "one unknown sale" do
|
|
||||||
sale = Sale.create(user)
|
|
||||||
shopping_cart = ShoppingCart.create(user, jam_track)
|
|
||||||
SaleLineItem.create_from_shopping_cart(sale, shopping_cart, 'some_recurly_uuid')
|
|
||||||
|
|
||||||
check_integrity = Sale.check_integrity
|
|
||||||
r = check_integrity[0]
|
|
||||||
r.total.to_i.should eq(1)
|
|
||||||
r.not_known.to_i.should eq(1)
|
|
||||||
r.succeeded.to_i.should eq(0)
|
|
||||||
r.failed.to_i.should eq(0)
|
|
||||||
r.refunded.to_i.should eq(0)
|
|
||||||
r.voided.to_i.should eq(0)
|
r.voided.to_i.should eq(0)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "one succeeded sale" do
|
it "one succeeded sale" do
|
||||||
sale = Sale.create(user)
|
sale = Sale.create_jam_track_sale(user)
|
||||||
shopping_cart = ShoppingCart.create(user, jam_track)
|
shopping_cart = ShoppingCart.create(user, jam_track)
|
||||||
SaleLineItem.create_from_shopping_cart(sale, shopping_cart, 'some_recurly_uuid')
|
SaleLineItem.create_from_shopping_cart(sale, shopping_cart, nil, 'some_recurly_invoice_id', nil)
|
||||||
FactoryGirl.create(:recurly_transaction_web_hook, subscription_id: 'some_recurly_uuid')
|
|
||||||
|
|
||||||
|
check_integrity = Sale.check_integrity_of_jam_track_sales
|
||||||
check_integrity = Sale.check_integrity
|
|
||||||
r = check_integrity[0]
|
r = check_integrity[0]
|
||||||
r.total.to_i.should eq(1)
|
r.total.to_i.should eq(1)
|
||||||
r.not_known.to_i.should eq(0)
|
|
||||||
r.succeeded.to_i.should eq(1)
|
|
||||||
r.failed.to_i.should eq(0)
|
|
||||||
r.refunded.to_i.should eq(0)
|
|
||||||
r.voided.to_i.should eq(0)
|
r.voided.to_i.should eq(0)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "one failed sale" do
|
|
||||||
sale = Sale.create(user)
|
|
||||||
shopping_cart = ShoppingCart.create(user, jam_track)
|
|
||||||
SaleLineItem.create_from_shopping_cart(sale, shopping_cart, 'some_recurly_uuid')
|
|
||||||
FactoryGirl.create(:recurly_transaction_web_hook_failed, subscription_id: 'some_recurly_uuid')
|
|
||||||
|
|
||||||
check_integrity = Sale.check_integrity
|
it "one voided sale" do
|
||||||
|
sale = Sale.create_jam_track_sale(user)
|
||||||
|
sale.recurly_invoice_id = 'some_recurly_invoice_id'
|
||||||
|
sale.save!
|
||||||
|
shopping_cart = ShoppingCart.create(user, jam_track)
|
||||||
|
SaleLineItem.create_from_shopping_cart(sale, shopping_cart, nil, 'some_recurly_invoice_id', nil)
|
||||||
|
FactoryGirl.create(:recurly_transaction_web_hook, transaction_type: RecurlyTransactionWebHook::VOID, invoice_id: 'some_recurly_invoice_id')
|
||||||
|
|
||||||
|
check_integrity = Sale.check_integrity_of_jam_track_sales
|
||||||
r = check_integrity[0]
|
r = check_integrity[0]
|
||||||
r.total.to_i.should eq(1)
|
r.total.to_i.should eq(1)
|
||||||
r.not_known.to_i.should eq(0)
|
r.voided.to_i.should eq(1)
|
||||||
r.succeeded.to_i.should eq(0)
|
|
||||||
r.failed.to_i.should eq(1)
|
|
||||||
r.refunded.to_i.should eq(0)
|
|
||||||
r.voided.to_i.should eq(0)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -86,42 +86,7 @@ describe RecurlyClient do
|
||||||
found.state.should eq('closed')
|
found.state.should eq('closed')
|
||||||
end
|
end
|
||||||
|
|
||||||
it "can place order" do
|
=begin
|
||||||
sale = Sale.create(@user)
|
|
||||||
sale = Sale.find(sale.id)
|
|
||||||
shopping_cart = ShoppingCart.create @user, @jamtrack, 1, true
|
|
||||||
history_items = @client.payment_history(@user).length
|
|
||||||
@client.find_or_create_account(@user, @billing_info)
|
|
||||||
expect{@client.place_order(@user, @jamtrack, shopping_cart, sale)}.not_to raise_error()
|
|
||||||
|
|
||||||
# verify jam_track_rights data
|
|
||||||
@user.jam_track_rights.should_not be_nil
|
|
||||||
@user.jam_track_rights.should have(1).items
|
|
||||||
@user.jam_track_rights.last.jam_track.id.should eq(@jamtrack.id)
|
|
||||||
|
|
||||||
# verify sales data
|
|
||||||
sale = Sale.find(sale.id)
|
|
||||||
sale.sale_line_items.length.should == 1
|
|
||||||
sale_line_item = sale.sale_line_items[0]
|
|
||||||
sale_line_item.product_type.should eq(JamTrack::PRODUCT_TYPE)
|
|
||||||
sale_line_item.unit_price.should eq(@jamtrack.price)
|
|
||||||
sale_line_item.quantity.should eq(1)
|
|
||||||
sale_line_item.free.should eq(1)
|
|
||||||
sale_line_item.sales_tax.should be_nil
|
|
||||||
sale_line_item.shipping_handling.should eq(0)
|
|
||||||
sale_line_item.recurly_plan_code.should eq(@jamtrack.plan_code)
|
|
||||||
sale_line_item.product_id.should eq(@jamtrack.id)
|
|
||||||
sale_line_item.recurly_subscription_uuid.should_not be_nil
|
|
||||||
sale_line_item.recurly_subscription_uuid.should eq(@user.jam_track_rights.last.recurly_subscription_uuid)
|
|
||||||
|
|
||||||
# verify subscription is in Recurly
|
|
||||||
subs = @client.get_account(@user).subscriptions
|
|
||||||
subs.should_not be_nil
|
|
||||||
subs.should have(1).items
|
|
||||||
|
|
||||||
@client.payment_history(@user).should have(history_items+1).items
|
|
||||||
end
|
|
||||||
|
|
||||||
it "can refund subscription" do
|
it "can refund subscription" do
|
||||||
sale = Sale.create(@user)
|
sale = Sale.create(@user)
|
||||||
shopping_cart = ShoppingCart.create @user, @jamtrack, 1
|
shopping_cart = ShoppingCart.create @user, @jamtrack, 1
|
||||||
|
|
@ -141,18 +106,7 @@ describe RecurlyClient do
|
||||||
@jamtrack.reload
|
@jamtrack.reload
|
||||||
@jamtrack.jam_track_rights.should have(0).items
|
@jamtrack.jam_track_rights.should have(0).items
|
||||||
end
|
end
|
||||||
|
=end
|
||||||
|
|
||||||
it "detects error on double order" do
|
|
||||||
sale = Sale.create(@user)
|
|
||||||
shopping_cart = ShoppingCart.create @user, @jamtrack, 1
|
|
||||||
@client.find_or_create_account(@user, @billing_info)
|
|
||||||
jam_track_right = @client.place_order(@user, @jamtrack, shopping_cart, sale)
|
|
||||||
jam_track_right.recurly_subscription_uuid.should_not be_nil
|
|
||||||
|
|
||||||
shopping_cart = ShoppingCart.create @user, @jamtrack, 1
|
|
||||||
jam_track_right2 = @client.place_order(@user, @jamtrack, shopping_cart, sale)
|
|
||||||
jam_track_right.should eq(jam_track_right2)
|
|
||||||
jam_track_right.recurly_subscription_uuid.should eq(jam_track_right.recurly_subscription_uuid)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,14 @@ JAMKAZAM_TESTING_BUCKET = 'jamkazam-testing' # cuz i'm not comfortable using aws
|
||||||
def app_config
|
def app_config
|
||||||
klass = Class.new do
|
klass = Class.new do
|
||||||
|
|
||||||
|
def email_alerts_alias
|
||||||
|
'alerts@jamkazam.com'
|
||||||
|
end
|
||||||
|
|
||||||
|
def email_generic_from
|
||||||
|
'nobody@jamkazam.com'
|
||||||
|
end
|
||||||
|
|
||||||
def aws_bucket
|
def aws_bucket
|
||||||
JAMKAZAM_TESTING_BUCKET
|
JAMKAZAM_TESTING_BUCKET
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,7 @@
|
||||||
var sub_total = 0.0
|
var sub_total = 0.0
|
||||||
var taxes = 0.0
|
var taxes = 0.0
|
||||||
$.each(carts, function(index, cart) {
|
$.each(carts, function(index, cart) {
|
||||||
sub_total += parseFloat(cart.product_info.total_price)
|
sub_total += parseFloat(cart.product_info.real_price)
|
||||||
});
|
});
|
||||||
if(carts.length == 0) {
|
if(carts.length == 0) {
|
||||||
data.grand_total = '-.--'
|
data.grand_total = '-.--'
|
||||||
|
|
@ -147,68 +147,45 @@
|
||||||
|
|
||||||
var planPricing = {}
|
var planPricing = {}
|
||||||
|
|
||||||
|
|
||||||
|
var priceElement = $screen.find('.order-right-page .plan.jamtrack')
|
||||||
|
|
||||||
|
if(priceElement.length == 0) {
|
||||||
|
logger.error("unable to find price element for jamtrack");
|
||||||
|
app.notify({title: "Error Encountered", text: "Unable to find plan info for jam track"})
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.debug("creating recurly pricing element for plan: " + gon.recurly_tax_estimate_jam_track_plan)
|
||||||
|
|
||||||
|
var effectiveQuantity = 0
|
||||||
|
|
||||||
context._.each(carts, function(cart) {
|
context._.each(carts, function(cart) {
|
||||||
var priceElement = $screen.find('.order-right-page .plan[data-plan-code="' + cart.product_info.plan_code +'"]')
|
effectiveQuantity += cart.product_info.quantity - cart.product_info.marked_for_redeem
|
||||||
|
|
||||||
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.grand-total').text('$' + totalPrice.toFixed(2))
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
logger.debug("still waiting on more plans to resolve")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
pricing.attach(priceElement.eq(0))
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
var pricing = context.recurly.Pricing();
|
||||||
|
pricing.plan_code = gon.recurly_tax_estimate_jam_track_plan;
|
||||||
|
pricing.resolved = false;
|
||||||
|
pricing.effective_quantity = 1
|
||||||
|
|
||||||
|
// 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 totalTax = 0;
|
||||||
|
var totalPrice = 0;
|
||||||
|
|
||||||
|
var unitTax = Number(pricing.price.now.tax) * effectiveQuantity;
|
||||||
|
totalTax += unitTax;
|
||||||
|
|
||||||
|
var totalUnitPrice = Number(pricing.price.now.total) * effectiveQuantity;
|
||||||
|
totalPrice += totalUnitPrice;
|
||||||
|
|
||||||
|
$screen.find('.order-right-page .order-items-value.taxes').text('$' + totalTax.toFixed(2))
|
||||||
|
$screen.find('.order-right-page .order-items-value.grand-total').text('$' + totalPrice.toFixed(2))
|
||||||
|
})
|
||||||
|
|
||||||
|
pricing.attach(priceElement.eq(0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,27 +18,27 @@ class ApiRecurlyController < ApiController
|
||||||
|
|
||||||
|
|
||||||
if current_user
|
if current_user
|
||||||
# keep reuse card up-to-date
|
# keep reuse card up-to-date
|
||||||
User.where(id: current_user.id).update_all(reuse_card: params[:reuse_card_next_time])
|
User.where(id: current_user.id).update_all(reuse_card: params[:reuse_card_next_time])
|
||||||
else
|
else
|
||||||
options = {
|
options = {
|
||||||
remote_ip: request.remote_ip,
|
remote_ip: request.remote_ip,
|
||||||
first_name: billing_info[:first_name],
|
first_name: billing_info[:first_name],
|
||||||
last_name: billing_info[:last_name],
|
last_name: billing_info[:last_name],
|
||||||
email: params[:email],
|
email: params[:email],
|
||||||
password: params[:password],
|
password: params[:password],
|
||||||
password_confirmation: params[:password],
|
password_confirmation: params[:password],
|
||||||
terms_of_service: terms_of_service,
|
terms_of_service: terms_of_service,
|
||||||
instruments: [{ :instrument_id => 'other', :proficiency_level => 1, :priority => 1 }],
|
instruments: [{:instrument_id => 'other', :proficiency_level => 1, :priority => 1}],
|
||||||
birth_date: nil,
|
birth_date: nil,
|
||||||
location: { :country => billing_info[:country], :state => billing_info[:state], :city => billing_info[:city]},
|
location: {:country => billing_info[:country], :state => billing_info[:state], :city => billing_info[:city]},
|
||||||
musician: true,
|
musician: true,
|
||||||
skip_recaptcha: true,
|
skip_recaptcha: true,
|
||||||
invited_user: nil,
|
invited_user: nil,
|
||||||
fb_signup: nil,
|
fb_signup: nil,
|
||||||
signup_confirm_url: ApplicationHelper.base_uri(request) + "/confirm",
|
signup_confirm_url: ApplicationHelper.base_uri(request) + "/confirm",
|
||||||
any_user: any_user,
|
any_user: any_user,
|
||||||
reuse_card: reuse_card_next_time
|
reuse_card: reuse_card_next_time
|
||||||
}
|
}
|
||||||
|
|
||||||
user = UserManager.new.signup(options)
|
user = UserManager.new.signup(options)
|
||||||
|
|
@ -61,9 +61,9 @@ class ApiRecurlyController < ApiController
|
||||||
@account = @client.find_or_create_account(current_user, billing_info)
|
@account = @client.find_or_create_account(current_user, billing_info)
|
||||||
end
|
end
|
||||||
|
|
||||||
render :json=>account_json(@account)
|
render :json => account_json(@account)
|
||||||
rescue RecurlyClientError => x
|
rescue RecurlyClientError => x
|
||||||
render json: { :message => x.inspect, errors: x.errors }, :status => 404
|
render json: {:message => x.inspect, errors: x.errors}, :status => 404
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -71,86 +71,80 @@ class ApiRecurlyController < ApiController
|
||||||
@client.delete_account(current_user)
|
@client.delete_account(current_user)
|
||||||
render json: {}, status: 200
|
render json: {}, status: 200
|
||||||
rescue RecurlyClientError => x
|
rescue RecurlyClientError => x
|
||||||
render json: { :message => x.inspect, errors: x.errors}, :status => 404
|
render json: {:message => x.inspect, errors: x.errors}, :status => 404
|
||||||
end
|
end
|
||||||
|
|
||||||
# get Recurly account
|
# get Recurly account
|
||||||
def get_account
|
def get_account
|
||||||
@account = @client.get_account(current_user)
|
@account = @client.get_account(current_user)
|
||||||
|
|
||||||
render :json=>account_json(@account)
|
render :json => account_json(@account)
|
||||||
rescue RecurlyClientError => e
|
rescue RecurlyClientError => e
|
||||||
render json: { message: x.inspect, errors: x.errors}, :status => 404
|
render json: {message: x.inspect, errors: x.errors}, :status => 404
|
||||||
end
|
end
|
||||||
|
|
||||||
# get Recurly payment history
|
# get Recurly payment history
|
||||||
def payment_history
|
def payment_history
|
||||||
@payments=@client.payment_history(current_user)
|
@payments=@client.payment_history(current_user)
|
||||||
render :json=>{payments: @payments}
|
render :json => {payments: @payments}
|
||||||
rescue RecurlyClientError => x
|
rescue RecurlyClientError => x
|
||||||
render json: { message: x.inspect, errors: x.errors}, :status => 404
|
render json: {message: x.inspect, errors: x.errors}, :status => 404
|
||||||
end
|
end
|
||||||
|
|
||||||
# update Recurly account
|
# update Recurly account
|
||||||
def update_account
|
def update_account
|
||||||
@account=@client.update_account(current_user, params[:billing_info])
|
@account=@client.update_account(current_user, params[:billing_info])
|
||||||
render :json=>account_json(@account)
|
render :json => account_json(@account)
|
||||||
rescue RecurlyClientError => x
|
rescue RecurlyClientError => x
|
||||||
render json: { message: x.inspect, errors: x.errors}, :status => 404
|
render json: {message: x.inspect, errors: x.errors}, :status => 404
|
||||||
end
|
end
|
||||||
|
|
||||||
# get Billing Information
|
# get Billing Information
|
||||||
def billing_info
|
def billing_info
|
||||||
@account = @client.get_account(current_user)
|
@account = @client.get_account(current_user)
|
||||||
if @account
|
if @account
|
||||||
render :json=> account_json(@account)
|
render :json => account_json(@account)
|
||||||
else
|
else
|
||||||
render :json=> {}, :status => 404
|
render :json => {}, :status => 404
|
||||||
end
|
end
|
||||||
rescue RecurlyClientError => x
|
rescue RecurlyClientError => x
|
||||||
render json: { message: x.inspect, errors: x.errors}, :status => 404
|
render json: {message: x.inspect, errors: x.errors}, :status => 404
|
||||||
end
|
end
|
||||||
|
|
||||||
# update Billing Information
|
# update Billing Information
|
||||||
def update_billing_info
|
def update_billing_info
|
||||||
@account=@client.update_billing_info(current_user, params[:billing_info])
|
@account = @client.update_billing_info(current_user, params[:billing_info])
|
||||||
render :json=> account_json(@account)
|
render :json => account_json(@account)
|
||||||
rescue RecurlyClientError => x
|
rescue RecurlyClientError => x
|
||||||
render json: { message: x.inspect, errors: x.errors}, :status => 404
|
render json: {message: x.inspect, errors: x.errors}, :status => 404
|
||||||
end
|
end
|
||||||
|
|
||||||
def place_order
|
def place_order
|
||||||
error=nil
|
error=nil
|
||||||
response = {jam_tracks:[]}
|
response = {jam_tracks: []}
|
||||||
|
|
||||||
sale = Sale.create(current_user)
|
sales = Sale.place_order(current_user, current_user.shopping_carts)
|
||||||
|
|
||||||
if sale.valid?
|
sales.each do |sale|
|
||||||
current_user.shopping_carts.each do |shopping_cart|
|
if sale.is_jam_track_sale?
|
||||||
jam_track = shopping_cart.cart_product
|
sale.sale_line_items.each do |line_item|
|
||||||
|
jam_track = line_item.product
|
||||||
# if shopping_cart has any marked_for_redeem, then we zero out the price by passing in 'free'
|
jam_track_right = jam_track.right_for_user(current_user)
|
||||||
# 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
|
response[:jam_tracks] << {name: jam_track.name, id: jam_track.id, jam_track_right_id: jam_track_right.id, version: jam_track.version}
|
||||||
|
end
|
||||||
jam_track_right = @client.place_order(current_user, jam_track, shopping_cart, sale)
|
|
||||||
# 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
|
||||||
else
|
|
||||||
error = 'can not create sale'
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if error
|
if error
|
||||||
render json: { errors: {message:error}}, :status => 404
|
render json: {errors: {message: error}}, :status => 404
|
||||||
else
|
else
|
||||||
render :json=>response, :status=>200
|
render :json => response, :status => 200
|
||||||
end
|
end
|
||||||
rescue RecurlyClientError => x
|
rescue RecurlyClientError => x
|
||||||
render json: { message: x.inspect, errors: x.errors}, :status => 404
|
render json: {message: x.inspect, errors: x.errors}, :status => 404
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
def create_client
|
def create_client
|
||||||
@client = RecurlyClient.new
|
@client = RecurlyClient.new
|
||||||
end
|
end
|
||||||
|
|
@ -173,5 +167,5 @@ private
|
||||||
billing_info: billing_info
|
billing_info: billing_info
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
end # class
|
end # class
|
||||||
|
|
@ -16,6 +16,7 @@ class ClientsController < ApplicationController
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
gon.recurly_tax_estimate_jam_track_plan = Rails.application.config.recurly_tax_estimate_jam_track_plan
|
||||||
render :layout => 'client'
|
render :layout => 'client'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -115,10 +115,8 @@ script type='text/template' id='template-order-content'
|
||||||
.order-right-page
|
.order-right-page
|
||||||
h2 PLACE ORDER
|
h2 PLACE ORDER
|
||||||
.recurly-data.hidden
|
.recurly-data.hidden
|
||||||
= "{% _.each(data.carts, function(cart) { %}"
|
.plan.jamtrack data-plan-code="{{gon.recurly_tax_estimate_jam_track_plan}}"
|
||||||
.plan data-plan-code="{{cart.product_info.plan_code}}"
|
input data-recurly="plan" type="text" value="{{gon.recurly_tax_estimate_jam_track_plan}}"
|
||||||
input data-recurly="plan" type="text" value="{{cart.product_info.plan_code}}"
|
|
||||||
= "{% }); %}"
|
|
||||||
.order-summary
|
.order-summary
|
||||||
.place-order-center
|
.place-order-center
|
||||||
a.button-orange.place-order href="#" PLACE YOUR ORDER
|
a.button-orange.place-order href="#" PLACE YOUR ORDER
|
||||||
|
|
|
||||||
|
|
@ -220,7 +220,7 @@ if defined?(Bundler)
|
||||||
# amount of time before we think the queue is stuck
|
# amount of time before we think the queue is stuck
|
||||||
config.signing_job_queue_max_time = 20 # 20 seconds
|
config.signing_job_queue_max_time = 20 # 20 seconds
|
||||||
|
|
||||||
config.email_alerts_alias = 'nobody@jamkazam.com' # should be used for 'oh no' server down/service down sorts of emails
|
config.email_alerts_alias = 'alerts@jamkazam.com' # should be used for 'oh no' server down/service down sorts of emails
|
||||||
config.email_generic_from = 'nobody@jamkazam.com'
|
config.email_generic_from = 'nobody@jamkazam.com'
|
||||||
config.email_smtp_address = 'smtp.sendgrid.net'
|
config.email_smtp_address = 'smtp.sendgrid.net'
|
||||||
config.email_smtp_port = 587
|
config.email_smtp_port = 587
|
||||||
|
|
@ -323,5 +323,6 @@ if defined?(Bundler)
|
||||||
config.one_free_jamtrack_per_user = true
|
config.one_free_jamtrack_per_user = true
|
||||||
|
|
||||||
config.nominated_jam_track = 'jamtrack-pearljam-alive'
|
config.nominated_jam_track = 'jamtrack-pearljam-alive'
|
||||||
|
config.recurly_tax_estimate_jam_track_plan = 'jamtrack-acdc-backinblack'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -40,8 +40,6 @@ describe "Checkout", :js => true, :type => :feature, :capybara_feature => true d
|
||||||
|
|
||||||
# make sure plans are there
|
# make sure plans are there
|
||||||
@recurlyClient.create_jam_track_plan(@jamtrack_acdc_backinblack) unless @recurlyClient.find_jam_track_plan(@jamtrack_acdc_backinblack)
|
@recurlyClient.create_jam_track_plan(@jamtrack_acdc_backinblack) unless @recurlyClient.find_jam_track_plan(@jamtrack_acdc_backinblack)
|
||||||
@recurlyClient.create_jam_track_plan(@jamtrack_pearljam_evenflow) unless @recurlyClient.find_jam_track_plan(@jamtrack_pearljam_evenflow)
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -552,7 +550,7 @@ describe "Checkout", :js => true, :type => :feature, :capybara_feature => true d
|
||||||
sale = user.sales.first
|
sale = user.sales.first
|
||||||
sale.sale_line_items.length.should eq(2)
|
sale.sale_line_items.length.should eq(2)
|
||||||
|
|
||||||
acdc_sale = SaleLineItem.find_by_recurly_subscription_uuid(acdc.recurly_subscription_uuid)
|
acdc_sale = SaleLineItem.find_by_recurly_adjustment_uuid(acdc.recurly_adjustment_uuid)
|
||||||
acdc_sale.recurly_plan_code.should eq(jamtrack_acdc_backinblack.plan_code)
|
acdc_sale.recurly_plan_code.should eq(jamtrack_acdc_backinblack.plan_code)
|
||||||
acdc_sale.product_type.should eq('JamTrack')
|
acdc_sale.product_type.should eq('JamTrack')
|
||||||
acdc_sale.product_id.should eq(jamtrack_acdc_backinblack.id)
|
acdc_sale.product_id.should eq(jamtrack_acdc_backinblack.id)
|
||||||
|
|
@ -560,7 +558,7 @@ describe "Checkout", :js => true, :type => :feature, :capybara_feature => true d
|
||||||
acdc_sale.free.should eq(0)
|
acdc_sale.free.should eq(0)
|
||||||
acdc_sale.unit_price.should eq(1.99)
|
acdc_sale.unit_price.should eq(1.99)
|
||||||
acdc_sale.sale.should eq(sale)
|
acdc_sale.sale.should eq(sale)
|
||||||
pearljam_sale = SaleLineItem.find_by_recurly_subscription_uuid(pearljam.recurly_subscription_uuid)
|
pearljam_sale = SaleLineItem.find_by_recurly_adjustment_uuid(pearljam.recurly_adjustment_uuid)
|
||||||
pearljam_sale.recurly_plan_code.should eq(jamtrack_pearljam_evenflow.plan_code)
|
pearljam_sale.recurly_plan_code.should eq(jamtrack_pearljam_evenflow.plan_code)
|
||||||
pearljam_sale.product_type.should eq('JamTrack')
|
pearljam_sale.product_type.should eq('JamTrack')
|
||||||
pearljam_sale.product_id.should eq(jamtrack_pearljam_evenflow.id)
|
pearljam_sale.product_id.should eq(jamtrack_pearljam_evenflow.id)
|
||||||
|
|
@ -660,7 +658,7 @@ describe "Checkout", :js => true, :type => :feature, :capybara_feature => true d
|
||||||
guy.sales.length.should eq(1)
|
guy.sales.length.should eq(1)
|
||||||
sale = guy.sales.first
|
sale = guy.sales.first
|
||||||
sale.sale_line_items.length.should eq(1)
|
sale.sale_line_items.length.should eq(1)
|
||||||
acdc_sale = SaleLineItem.find_by_recurly_subscription_uuid(jam_track_right.recurly_subscription_uuid)
|
acdc_sale = SaleLineItem.find_by_recurly_adjustment_uuid(jam_track_right.recurly_adjustment_uuid)
|
||||||
acdc_sale.recurly_plan_code.should eq(jamtrack_acdc_backinblack.plan_code)
|
acdc_sale.recurly_plan_code.should eq(jamtrack_acdc_backinblack.plan_code)
|
||||||
acdc_sale.product_type.should eq('JamTrack')
|
acdc_sale.product_type.should eq('JamTrack')
|
||||||
acdc_sale.product_id.should eq(jamtrack_acdc_backinblack.id)
|
acdc_sale.product_id.should eq(jamtrack_acdc_backinblack.id)
|
||||||
|
|
@ -710,7 +708,7 @@ describe "Checkout", :js => true, :type => :feature, :capybara_feature => true d
|
||||||
guy.sales.length.should eq(2)
|
guy.sales.length.should eq(2)
|
||||||
sale = guy.sales.last
|
sale = guy.sales.last
|
||||||
sale.sale_line_items.length.should eq(1)
|
sale.sale_line_items.length.should eq(1)
|
||||||
acdc_sale = SaleLineItem.find_by_recurly_subscription_uuid(jam_track_right.recurly_subscription_uuid)
|
acdc_sale = SaleLineItem.find_by_recurly_adjustment_uuid(jam_track_right.recurly_adjustment_uuid)
|
||||||
acdc_sale.recurly_plan_code.should eq(jamtrack_pearljam_evenflow.plan_code)
|
acdc_sale.recurly_plan_code.should eq(jamtrack_pearljam_evenflow.plan_code)
|
||||||
acdc_sale.product_type.should eq('JamTrack')
|
acdc_sale.product_type.should eq('JamTrack')
|
||||||
acdc_sale.product_id.should eq(jamtrack_pearljam_evenflow.id)
|
acdc_sale.product_id.should eq(jamtrack_pearljam_evenflow.id)
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ describe "Individual JamTrack Band", :js => true, :type => :feature, :capybara_f
|
||||||
|
|
||||||
@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')
|
@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')
|
||||||
|
|
||||||
# make sure plans are there
|
# make sure tax estimate plans are there
|
||||||
@recurlyClient.create_jam_track_plan(@jamtrack_acdc_backinblack) unless @recurlyClient.find_jam_track_plan(@jamtrack_acdc_backinblack)
|
@recurlyClient.create_jam_track_plan(@jamtrack_acdc_backinblack) unless @recurlyClient.find_jam_track_plan(@jamtrack_acdc_backinblack)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -187,6 +187,9 @@ bputs "before register capybara"
|
||||||
config.include Requests::JsonHelpers, type: :request
|
config.include Requests::JsonHelpers, type: :request
|
||||||
config.include Requests::FeatureHelpers, type: :feature
|
config.include Requests::FeatureHelpers, type: :feature
|
||||||
|
|
||||||
|
# Use the specified formatter
|
||||||
|
#config.formatter = :documentation
|
||||||
|
|
||||||
config.before(:suite) do
|
config.before(:suite) do
|
||||||
tests_started = true
|
tests_started = true
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue