module JamRuby class SaleLineItem < ActiveRecord::Base JAMBLASTER = 'JamBlaster' JAMCLOUD = 'JamCloud' JAMTRACK = 'JamTrack' GIFTCARD = 'GiftCardType' LESSON = 'LessonPackageType' POSACARD = 'PosaCard' SUBSCRIPTION = 'Subscription' belongs_to :sale, class_name: 'JamRuby::Sale' belongs_to :jam_track, class_name: 'JamRuby::JamTrack' belongs_to :jam_track_right, class_name: 'JamRuby::JamTrackRight' belongs_to :gift_card, class_name: 'JamRuby::GiftCard' belongs_to :lesson_package_purchase, class_name: 'JamRuby::LessonPackagePurchase' belongs_to :retailer, class_name: 'JamRuby::Retailer' # deprecated; use affiliate_distribution !! belongs_to :affiliate_referral, class_name: 'JamRuby::AffiliatePartner', foreign_key: :affiliate_referral_id has_many :affiliate_distributions, class_name: 'JamRuby::AffiliateDistribution' has_many :recurly_transactions, class_name: 'JamRuby::RecurlyTransactionWebHook', inverse_of: :sale_line_item, foreign_key: 'subscription_id', primary_key: 'recurly_subscription_uuid' validates :product_type, inclusion: {in: [JAMBLASTER, JAMCLOUD, JAMTRACK, GIFTCARD, LESSON, POSACARD, SUBSCRIPTION]} validates :unit_price, numericality: {only_integer: false} validates :quantity, numericality: {only_integer: true} validates :free, numericality: {only_integer: true} validates :sales_tax, numericality: {only_integer: false}, allow_nil: true validates :shipping_handling, numericality: {only_integer: false} validates :affiliate_referral_fee_in_cents, numericality: {only_integer: false}, allow_nil: true validates :recurly_plan_code, presence:true validates :sale, presence:true def is_jam_track? product_type == JAMTRACK end def is_gift_card? product_type == GIFTCARD end def is_subscription? product_type == SUBSCRIPTION end def product if product_type == JAMTRACK JamTrack.find_by_id(product_id) elsif product_type == SUBSCRIPTION {name: product_id} elsif product_type == GIFTCARD GiftCardType.find_by_id(product_id) elsif product_type == LESSON lesson_package_purchase elsif product_type == POSACARD PosaCard.find(product_id) else raise 'unsupported product type' end end def product_info item = product { name: product.name, product_type: product_type } if item end def state voided = false refunded = false failed = false succeeded = false recurly_transactions.each do |transaction| if transaction.transaction_type == RecurlyTransactionWebHook::VOID voided = true elsif transaction.transaction_type == RecurlyTransactionWebHook::REFUND refunded = true elsif transaction.transaction_type == RecurlyTransactionWebHook::FAILED_PAYMENT failed = true elsif transaction.transaction_type == RecurlyTransactionWebHook::SUCCESSFUL_PAYMENT succeeded = true end end { void: voided, refund: refunded, fail: failed, success: succeeded } end # in a shopping-cart less world (ios purchase), let's reuse as much logic as possible def self.create_from_jam_track(current_user, sale, jam_track, mark_redeem) shopping_cart = ShoppingCart.create(current_user, jam_track, 1, mark_redeem) line_item = create_from_shopping_cart(sale, shopping_cart, nil, nil, nil) shopping_cart.destroy line_item end def add_referral_if_needed(user, shopping_cart, lesson_booking) # if the teacher came from an affiliate, this is our chance to account for that (the student's affiliate status was accounted for in create_from_shopping_cart) referral_info = user.should_attribute_sale?(shopping_cart, lesson_booking) if referral_info self.affiliate_distributions << AffiliateDistribution.create(user.affiliate_referral, referral_info[:fee_in_cents], self) self.save! end end def self.create_from_subscription(current_user, sale, plan_code, recurly_response) sale_line_item = SaleLineItem.new sale_line_item.product_type = SUBSCRIPTION sale_line_item.product_id = recurly_response.uuid sale_line_item.unit_price = recurly_response.unit_amount_in_cents sale_line_item.quantity = 1 sale_line_item.free = false sale_line_item.sales_tax = recurly_response.tax_in_cents sale_line_item.shipping_handling = 0 sale_line_item.recurly_plan_code = plan_code sale.sale_line_items << sale_line_item sale_line_item.save sale_line_item end # in a shopping-cart less world (ios purchase), let's reuse as much logic as possible def self.create_from_lesson_package(current_user, sale, lesson_package_type, lesson_booking) teacher = lesson_booking.teacher if lesson_booking shopping_cart = ShoppingCart.create(current_user, lesson_package_type, 1) line_item = create_from_shopping_cart(sale, shopping_cart, nil, nil, nil, lesson_booking) if lesson_booking teacher = lesson_booking.teacher student = lesson_booking.student if lesson_booking.is_test_drive? # no referral for test drives elsif lesson_booking.no_school_on_school_payment? # no referral; we don't make money on school-on-school else line_item.add_referral_if_needed(student, shopping_cart, lesson_booking) if lesson_booking.school.nil? line_item.add_referral_if_needed(teacher, shopping_cart, lesson_booking) end end end shopping_cart.destroy line_item end def self.associate_user_for_posa(posa_card, user) sale_line_item = SaleLineItem.where(product_type: POSACARD).where(product_id: posa_card.id).first if sale_line_item sale_line_item.sale.user = user sale_line_item.sale.save! end end def self.create_from_posa_card(sale, retailer, posa_card) product_info = posa_card.product_info sale_line_item = SaleLineItem.new sale_line_item.retailer = retailer sale_line_item.product_type = POSACARD sale_line_item.product_id = posa_card.id sale_line_item.unit_price = product_info[:price] sale_line_item.quantity = product_info[:quantity] sale_line_item.free = product_info[:marked_for_redeem] sale_line_item.sales_tax = nil sale_line_item.shipping_handling = 0 sale_line_item.recurly_plan_code = product_info[:plan_code] #referral_info = retailer.referral_info #if referral_info # sale_line_item.affiliate_distributions << AffiliateDistribution.create(retailer.affiliate_partner, referral_info[:fee_in_cents], sale_line_item) # sale_line_item.affiliate_referral = retailer.affiliate_partner # sale_line_item.affiliate_referral_fee_in_cents = referral_info[:fee_in_cents] #end sale.sale_line_items << sale_line_item sale_line_item.save sale_line_item end def self.create_from_shopping_cart(sale, shopping_cart, recurly_subscription_uuid, recurly_adjustment_uuid, recurly_adjustment_credit_uuid, instance = nil) product_info = shopping_cart.product_info(instance) sale.order_total = sale.order_total + product_info[:real_price] sale_line_item = SaleLineItem.new sale_line_item.product_type = shopping_cart.cart_type sale_line_item.variant = shopping_cart.variant sale_line_item.unit_price = product_info[:price] sale_line_item.quantity = product_info[:quantity] sale_line_item.free = product_info[:marked_for_redeem] sale_line_item.sales_tax = nil sale_line_item.shipping_handling = 0 sale_line_item.recurly_plan_code = product_info[:plan_code] sale_line_item.product_id = shopping_cart.cart_id sale_line_item.recurly_subscription_uuid = recurly_subscription_uuid sale_line_item.recurly_adjustment_uuid = recurly_adjustment_uuid sale_line_item.recurly_adjustment_credit_uuid = recurly_adjustment_credit_uuid # determine if we need to associate this sale with a partner user = shopping_cart.user referral_info = user.should_attribute_sale?(shopping_cart, instance) if !instance || !instance.is_a?(LessonBooking) # all affiliate stuff is handled elsewhere if referral_info sale_line_item.affiliate_distributions << AffiliateDistribution.create(user.affiliate_referral, referral_info[:fee_in_cents], sale_line_item) sale_line_item.affiliate_referral = user.affiliate_referral sale_line_item.affiliate_referral_fee_in_cents = referral_info[:fee_in_cents] end sale.sale_line_items << sale_line_item sale_line_item.save sale_line_item end end end