289 lines
9.3 KiB
Ruby
289 lines
9.3 KiB
Ruby
module JamRuby
|
|
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_accessor :skip_mix_check
|
|
|
|
validates_uniqueness_of :cart_id, scope: [:cart_type, :user_id, :anonymous_user_id]
|
|
|
|
belongs_to :user, :inverse_of => :shopping_carts, :class_name => "JamRuby::User", :foreign_key => "user_id"
|
|
|
|
validates :cart_id, presence: true
|
|
validates :cart_type, presence: true
|
|
validates :cart_class_name, presence: true
|
|
validates :marked_for_redeem, numericality: {only_integer: true}
|
|
#validate :not_mixed
|
|
|
|
default_scope { order('created_at DESC') }
|
|
|
|
def product_info(instance = nil)
|
|
product = self.cart_product
|
|
data = {type: cart_type, 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, free: free?, sales_region: product.sales_region, sale_display:product.sale_display, allow_free: allow_free(product)} unless product.nil?
|
|
if data && instance
|
|
data.merge!(instance.product_info)
|
|
end
|
|
data
|
|
end
|
|
|
|
# multiply quantity by price
|
|
def total_price(product)
|
|
quantity * product.price
|
|
end
|
|
|
|
# multiply (quantity - redeemable) by price
|
|
def real_price(product)
|
|
(quantity - marked_for_redeem) * product.price
|
|
end
|
|
|
|
def allow_free(product)
|
|
if(product.is_a?(JamTrack))
|
|
product.allow_free
|
|
else
|
|
false
|
|
end
|
|
end
|
|
|
|
def not_mixed
|
|
|
|
return if @skip_mix_check
|
|
existing_carts = []
|
|
this_user = any_user()
|
|
|
|
if this_user
|
|
existing_carts = this_user.shopping_carts
|
|
end
|
|
|
|
existing_carts = existing_carts.to_a
|
|
existing_carts << self
|
|
|
|
if Sale.is_mixed(existing_carts)
|
|
if free?
|
|
errors.add(:base, "You can not add a free JamTrack to a cart with non-free items. Please clear out your cart.")
|
|
return false
|
|
else
|
|
errors.add(:base, "You can not add a non-free JamTrack to a cart containing free items. Please clear out your cart.")
|
|
return false
|
|
end
|
|
end
|
|
|
|
false
|
|
end
|
|
|
|
def cart_product
|
|
self.cart_class_name.classify.constantize.find_by_id(self.cart_id) unless self.cart_class_name.blank?
|
|
end
|
|
|
|
def redeem(mark_redeem)
|
|
self.marked_for_redeem = mark_redeem ? 1 : 0
|
|
end
|
|
|
|
def free?
|
|
marked_for_redeem == quantity
|
|
end
|
|
|
|
def any_user
|
|
if user
|
|
user
|
|
elsif anonymous_user_id
|
|
AnonymousUser.new(anonymous_user_id, nil)
|
|
else
|
|
nil
|
|
end
|
|
end
|
|
|
|
def self.create user, product, quantity = 1, mark_redeem = false
|
|
|
|
cart = ShoppingCart.new
|
|
if user.is_a?(User)
|
|
cart.user = user
|
|
else
|
|
cart.anonymous_user_id = user.id
|
|
end
|
|
|
|
cart.cart_type = product.class::PRODUCT_TYPE
|
|
cart.cart_class_name = product.class.name
|
|
cart.cart_id = product.id
|
|
cart.quantity = quantity
|
|
cart.redeem(mark_redeem)
|
|
cart.save
|
|
cart
|
|
end
|
|
|
|
def is_jam_track?
|
|
cart_type == JamTrack::PRODUCT_TYPE
|
|
end
|
|
|
|
def is_gift_card?
|
|
cart_type == GiftCardType::PRODUCT_TYPE
|
|
end
|
|
|
|
def is_lesson?
|
|
cart_type == LessonPackageType::PRODUCT_TYPE
|
|
end
|
|
|
|
# returns an array of adjustments for the shopping cart
|
|
def create_adjustment_attributes(current_user)
|
|
raise "not a jam track or gift card" unless is_jam_track? || is_gift_card?
|
|
|
|
info = self.product_info
|
|
|
|
if free?
|
|
# create the credit, then the pseudo charge
|
|
[]
|
|
else
|
|
|
|
[
|
|
{
|
|
accounting_code: PURCHASE_NORMAL,
|
|
currency: 'USD',
|
|
unit_amount_in_cents: (info[:total_price] * 100).to_i,
|
|
description: info[:sale_display],
|
|
tax_exempt: false
|
|
}
|
|
]
|
|
end
|
|
end
|
|
|
|
def self.move_to_user(user, anonymous_user, shopping_carts)
|
|
shopping_carts.each do |shopping_cart|
|
|
if shopping_cart.is_jam_track?
|
|
mark_redeem = ShoppingCart.user_has_redeemable_jam_track?(user)
|
|
cart = ShoppingCart.create(user, shopping_cart.cart_product, shopping_cart.quantity, mark_redeem)
|
|
else
|
|
cart = ShoppingCart.create(user, shopping_cart.cart_product, shopping_cart.quantity, false)
|
|
end
|
|
|
|
end
|
|
|
|
anonymous_user.destroy_all_shopping_carts
|
|
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 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)
|
|
|
|
if any_user.has_redeemable_jamtrack || any_user.gifted_jamtracks > 0
|
|
|
|
free_in_cart = 0
|
|
|
|
any_user.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 == JamTrack::PRODUCT_TYPE
|
|
free_in_cart += shopping_cart.marked_for_redeem
|
|
end
|
|
end
|
|
|
|
any_user.free_jamtracks > free_in_cart
|
|
else
|
|
false
|
|
end
|
|
end
|
|
|
|
# adds a jam_track to cart, checking for promotions
|
|
def self.add_jam_track_to_cart(any_user, jam_track, clear:false)
|
|
cart = nil
|
|
ShoppingCart.transaction do
|
|
|
|
# if clear
|
|
if any_user.shopping_carts.length == 1 && any_user.shopping_carts[0].product_info[:allow_free] && (any_user.has_redeemable_jamtrack && any_user.gifted_jamtracks == 0) && jam_track.allow_free && any_user.free_jamtracks > 0 # clear
|
|
# if you are an anonymous user, we make sure there is nothing else in your shopping cart ... keep it clean for the 'new user rummaging around for a freebie scenario'
|
|
any_user.destroy_jam_track_shopping_carts
|
|
any_user.reload
|
|
end
|
|
|
|
mark_redeem = jam_track.allow_free ? ShoppingCart.user_has_redeemable_jam_track?(any_user) : false
|
|
cart = ShoppingCart.create(any_user, jam_track, 1, mark_redeem)
|
|
end
|
|
any_user.reload
|
|
cart
|
|
end
|
|
|
|
def self.add_item_to_cart(any_user, item)
|
|
cart = nil
|
|
ShoppingCart.transaction do
|
|
cart = ShoppingCart.create(any_user, item, 1, false)
|
|
end
|
|
cart
|
|
end
|
|
|
|
# deletes a jam track from the shopping cart, updating redeem flag as necessary
|
|
def self.remove_jam_track_from_cart(any_user, cart)
|
|
ShoppingCart.transaction do
|
|
cart.destroy
|
|
|
|
# so that user.shopping_carts reflects truth
|
|
any_user.reload
|
|
|
|
# check if we should move the redemption around automatically
|
|
mark_redeem = ShoppingCart.user_has_redeemable_jam_track?(any_user)
|
|
|
|
carts = any_user.shopping_carts
|
|
|
|
# if we find any carts on the account that are not redeemed, mark first one redeemable
|
|
if mark_redeem && carts.length > 0
|
|
carts.each do |cart|
|
|
if cart.marked_for_redeem == 0
|
|
if cart.quantity > 1
|
|
raise 'unknown situation for redeemption juggling'
|
|
end
|
|
cart.redeem(mark_redeem)
|
|
cart.save
|
|
break
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
def self.remove_item_from_cart(any_user, cart)
|
|
ShoppingCart.transaction do
|
|
cart.destroy
|
|
end
|
|
end
|
|
|
|
# if the number of items in the shopping cart is less than gifted_jamtracks on the user, then fix them all up
|
|
def self.apply_gifted_jamtracks(user)
|
|
jam_track_carts = user.shopping_carts.where(cart_type:JamTrack::PRODUCT_TYPE)
|
|
|
|
if jam_track_carts.count > user.gifted_jamtracks
|
|
# just whack everything in their shopping cart
|
|
user.destroy_all_shopping_carts
|
|
return
|
|
end
|
|
|
|
jam_track_carts.each do |cart|
|
|
cart.skip_mix_check = true
|
|
cart.marked_for_redeem = 1
|
|
cart.save!
|
|
end
|
|
end
|
|
|
|
def port(user, anonymous_user)
|
|
|
|
ShoppingCart.transaction do
|
|
move_to_user(user, anonymous_user, anonymous_user.shopping_carts)
|
|
end
|
|
end
|
|
end
|
|
end |