require 'spec_helper'

describe Sale do

  let(:user) { FactoryGirl.create(:user) }
  let(:user2) { FactoryGirl.create(:user) }
  let(:jam_track) { FactoryGirl.create(:jam_track) }
  let(:jam_track2) { FactoryGirl.create(:jam_track) }
  let(:jam_track3) { FactoryGirl.create(:jam_track) }
  let(:gift_card) { GiftCardType.jam_track_5 }
  let(:posa_card) {FactoryGirl.create(:posa_card)}
  let(:retailer) {FactoryGirl.create(:retailer)}

  after(:each) {
    Timecop.return
  }
  def assert_free_line_item(sale_line_item, jamtrack)
    sale_line_item.recurly_tax_in_cents.should be_nil
    sale_line_item.recurly_total_in_cents.should be_nil
    sale_line_item.recurly_currency.should be_nil
    sale_line_item.recurly_discount_in_cents.should be_nil
    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)
  end

  describe "posa_cards" do
    it "works" do
      posa_card.card_type.should eql PosaCard::JAM_TRACKS_5

      result = Sale.posa_activate(posa_card, retailer)
      posa_card.errors.any?.should be false
      posa_card.activated_at.should_not be_nil
      sale = result[:sale]

      sale = Sale.find(sale.id)
      sale.sale_line_items.count.should eql 1
      sale_line_item = sale.sale_line_items.first
      sale.retailer.should eql retailer
      sale.sale_type.should eql Sale::POSA_SALE
      sale_line_item.retailer.should eql retailer
      sale_line_item.unit_price.should eql 9.99 #
      sale_line_item.quantity.should eql 1
    end

    it "already activated" do
      result = Sale.posa_activate(posa_card, retailer)
      posa_card.activated_at.should_not be_nil
      posa_card.errors.any?.should be false
      sale = result[:sale]

      result2 = Sale.posa_activate(posa_card, retailer)
      posa_card.activated_at.should_not be_nil
      posa_card.errors.any?.should be true
      result2[:sale].should be_nil
      posa_card.errors[:activated_at].should eq ["already activated. Please give card to customer. Thank you!"]
    end
  end

  describe "index" do
    it "empty" do
      result = Sale.index(user)
      result[:query].length.should eq(0)
      result[:next].should eq(nil)
    end

    it "one" do
      sale = Sale.create_jam_track_sale(user)
      shopping_cart = ShoppingCart.create(user, jam_track)
      sale_line_item = SaleLineItem.create_from_shopping_cart(sale, shopping_cart, nil, 'some_adjustment_uuid', nil)

      result = Sale.index(user)
      result[:query].length.should eq(1)
      result[:next].should eq(nil)
    end

    it "user filtered correctly" do
      sale = Sale.create_jam_track_sale(user)
      shopping_cart = ShoppingCart.create(user, jam_track)
      sale_line_item = SaleLineItem.create_from_shopping_cart(sale, shopping_cart, nil, 'some_adjustment_uuid', nil)

      result = Sale.index(user)
      result[:query].length.should eq(1)
      result[:next].should eq(nil)

      sale2 = Sale.create_jam_track_sale(user2)
      shopping_cart = ShoppingCart.create(user2, jam_track)
      sale_line_item2 = SaleLineItem.create_from_shopping_cart(sale2, shopping_cart, nil, 'some_adjustment_uuid', nil)

      result = Sale.index(user)
      result[:query].length.should eq(1)
      result[:next].should eq(nil)
    end
  end


  describe "place_order" do

    let(:user) { FactoryGirl.create(:user) }
    let(:jamtrack) { FactoryGirl.create(:jam_track) }
    let(:jamtrack2) { FactoryGirl.create(:jam_track) }
    let(:jamtrack3) { FactoryGirl.create(:jam_track) }
    let(:jamtrack4) { FactoryGirl.create(:jam_track) }
    let(:jam_track_price_in_cents) { (jamtrack.price * 100).to_i }
    let(:gift_card_price_in_cents) { (gift_card.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
    }
    before {
      pending "Recurly test environment needs to be restored. It was deleted automatically by Recurly"
    }

    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 gift card" do
      shopping_cart = ShoppingCart.create user, gift_card, 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(gift_card_price_in_cents)
      sale.recurly_tax_in_cents.should eq(0)
      sale.recurly_total_in_cents.should eq(gift_card_price_in_cents)
      sale.recurly_currency.should eq('USD')

      sale.order_total.should eq(gift_card.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(gift_card_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(GiftCardType::PRODUCT_TYPE)
      sale_line_item.unit_price.should eq(gift_card.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(gift_card.plan_code)
      sale_line_item.product_id.should eq(gift_card.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_not be_nil

      # 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((gift_card.price * 100).to_i)
      purchase.accounting_code.should eq(ShoppingCart::PURCHASE_NORMAL)
      purchase.description.should eq("JamTracks Gift Card (5)")
      purchase.state.should eq('invoiced')
      purchase.uuid.should eq(sale_line_item.recurly_adjustment_uuid)

      sleep 2
      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((gift_card.price * 100).to_i)
      invoice.total_in_cents.should eq((gift_card.price * 100).to_i)
      #invoice.state.should eq('collected')

      # verify jam_track_rights data
      user.gift_card_purchases.should_not be_nil
      user.gift_card_purchases.should have(1).items
      user.gift_card_purchases.last.gift_card_type.should eq(GiftCardType.jam_track_5)
      user.has_redeemable_jamtrack.should be_true

      sale_line_item.affiliate_referral.should be_nil
      sale_line_item.affiliate_referral_fee_in_cents.should be_nil
    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 be_nil

      sale.recurly_subtotal_in_cents.should eq(0)
      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(0)
      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 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)
      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(0).items

      invoices = recurly_account.invoices
      invoices.should have(0).items


      # 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 two jamtracks 1 freebie, 1 purchased" do
      user.gifted_jamtracks = 2
      user.save!

      jamtrack.allow_free = false
      jamtrack.price =2.99
      jamtrack.save!

      shopping_cart1 = ShoppingCart.create user, jamtrack, 1, false
      shopping_cart2 = ShoppingCart.create user, jamtrack2, 1, true

      client.find_or_create_account(user, billing_info)

      sales = Sale.place_order(user, [shopping_cart1, shopping_cart2])

      user.reload
      user.sales.length.should eq(1)
      sale = sales[0]
      sale.reload

      sale.recurly_invoice_id.should_not be_nil

      sale.recurly_subtotal_in_cents.should eq(jamtrack.price * 100)
      sale.recurly_tax_in_cents.should eq(0)
      sale.recurly_total_in_cents.should eq(jamtrack.price * 100)
      sale.recurly_currency.should eq('USD')
      sale.order_total.should eq(jamtrack.price)
      sale.sale_line_items.length.should == 2

      sale.sale_line_items[0].free.should eql 0
      assert_free_line_item(sale.sale_line_items[1], jamtrack2)

      # verify jam_track_rights data
      right1 = JamTrackRight.where(user_id: user.id).where(jam_track_id: jamtrack.id).first
      right2 = JamTrackRight.where(user_id: user.id).where(jam_track_id: jamtrack2.id).first
      user.jam_track_rights.should have(2).items

      right1.redeemed.should be_false
      right2.redeemed.should be_true
      user.has_redeemable_jamtrack.should be_false
      user.gifted_jamtracks.should eq(2)

    end

    it "for two jam tracks (1 freebie, 1 gifted), then 1 gifted/1 pay" do
      user.gifted_jamtracks = 2
      user.save!

      shopping_cart1 = ShoppingCart.create user, jamtrack, 1, true
      shopping_cart2 = ShoppingCart.create user, jamtrack2, 1, true

      client.find_or_create_account(user, billing_info)

      sales = Sale.place_order(user, [shopping_cart1, shopping_cart2])

      user.reload
      user.sales.length.should eq(1)
      sale = sales[0]
      sale.reload

      sale.recurly_invoice_id.should be_nil

      sale.recurly_subtotal_in_cents.should eq(0)
      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 == 2

      assert_free_line_item(sale.sale_line_items[0], jamtrack)
      assert_free_line_item(sale.sale_line_items[1], jamtrack2)

      # verify jam_track_rights data
      right1 = JamTrackRight.where(user_id: user.id).where(jam_track_id: jamtrack.id).first
      right2 = JamTrackRight.where(user_id: user.id).where(jam_track_id: jamtrack2.id).first
      user.jam_track_rights.should have(2).items

      right1.redeemed.should be_true
      right2.redeemed.should be_true
      user.has_redeemable_jamtrack.should be_false
      user.gifted_jamtracks.should eq(1)


      # OK!  Now make a second purchase; this time, buy one free, one not free
      shopping_cart3 = ShoppingCart.create user, jamtrack3, 1, true

      client.find_or_create_account(user, billing_info)

      sales = Sale.place_order(user, [shopping_cart3])

      user.reload
      user.sales.length.should eq(2)
      sale = sales[0]
      sale.reload

      sale.recurly_invoice_id.should be_nil
      sale.recurly_subtotal_in_cents.should eq(0)
      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

      assert_free_line_item(sale.sale_line_items[0], jamtrack3)
    end

    it "for a free jam track with an affiliate association" do
      partner = FactoryGirl.create(:affiliate_partner)
      user.affiliate_referral = partner
      user.save!

      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 be_nil

      sale.recurly_subtotal_in_cents.should eq(0)
      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(0)
      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 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)
      sale_line_item.recurly_adjustment_credit_uuid.should eq(user.jam_track_rights.last.recurly_adjustment_credit_uuid)
      sale_line_item.affiliate_referral.should eq(partner)
      sale_line_item.affiliate_referral_fee_in_cents.should eq(0)

      # verify subscription is in Recurly
      recurly_account = client.get_account(user)
      adjustments = recurly_account.adjustments
      adjustments.should_not be_nil
      adjustments.should have(0).items

      invoices = recurly_account.invoices
      invoices.should have(0).items


      # 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", intermittent: true do
      # intermittent: sometimes recurly won't mark it 'collected' soon enough for the test to pass

      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 + ' - FOR USE ONLY WITHIN APP')
      purchase.state.should eq('invoiced')
      purchase.uuid.should eq(sale_line_item.recurly_adjustment_uuid)

      sleep 2
      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

      sale_line_item.affiliate_referral.should be_nil
      sale_line_item.affiliate_referral_fee_in_cents.should be_nil
    end


    it "for a normally priced jam track with an affiliate association" do
      user.has_redeemable_jamtrack = false
      partner = FactoryGirl.create(:affiliate_partner)
      user.affiliate_referral = partner
      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)
      sale_line_item.affiliate_referral.should eq(partner)
      sale_line_item.affiliate_referral_fee_in_cents.should eq(20)

      # 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 + " - FOR USE ONLY WITHIN APP")
      purchase.state.should eq('invoiced')
      purchase.uuid.should eq(sale_line_item.recurly_adjustment_uuid)

      sleep 2
      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(0).items # because the only successful purchase was a freebie, there should be no recurly adjustments
    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, false

      # 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[0][: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, false
      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(1).items # two adjustments are created for a free jamtrack; that should be all there is
    end
  end

  describe "lessons" do

    before {
      pending "Lessons paused"
    }

    let(:teacher_user) { FactoryGirl.create(:teacher_user) }
    let(:teacher) { teacher_user.teacher }
    let(:lesson_booking_slot_single1) { FactoryGirl.build(:lesson_booking_slot_single) }
    let(:lesson_booking_slot_single2) { FactoryGirl.build(:lesson_booking_slot_single) }
    let(:lesson_booking_slot_recurring1) { FactoryGirl.build(:lesson_booking_slot_recurring) }
    let(:lesson_booking_slot_recurring2) { FactoryGirl.build(:lesson_booking_slot_recurring) }
    let(:valid_single_slots) { [lesson_booking_slot_single1, lesson_booking_slot_single2] }
    let(:valid_recurring_slots) { [lesson_booking_slot_recurring1, lesson_booking_slot_recurring2] }
    let(:affiliate_partner) { FactoryGirl.create(:affiliate_partner) }
    let(:affiliate_partner2) { FactoryGirl.create(:affiliate_partner, lesson_rate: 0.30) }

    describe "single" do
      it "can succeed" do

        token = create_stripe_token
        result = user.payment_update({token: token, zip: '72205', normal: true})

        lesson_session = normal_lesson(user, teacher_user)

        # teacher & student get into session
        start = lesson_session.scheduled_start
        end_time = lesson_session.scheduled_start + (60 * lesson_session.duration)
        uh2 = FactoryGirl.create(:music_session_user_history, user: teacher_user, history: lesson_session.music_session, created_at: start, session_removed_at: end_time)
        # artificially end the session, which is covered by other background jobs
        lesson_session.music_session.session_removed_at = end_time
        lesson_session.music_session.save!

        Timecop.travel(end_time + 1)

        # bill the user
        LessonSession.hourly_check

        lesson_session.reload
        payment = lesson_session.lesson_payment_charge
        user.sales.count.should eql 1
        sale = user.sales.first
        sale.stripe_charge_id.should_not be_nil
        sale.recurly_tax_in_cents.should be 0
        sale.recurly_total_in_cents.should eql 3000
        sale.recurly_subtotal_in_cents.should eql 3000
        sale.recurly_currency.should eql 'USD'
        line_item = sale.sale_line_items[0]
        line_item.quantity.should eql 1
        line_item.product_type.should eql SaleLineItem::LESSON
        line_item.product_id.should eq LessonPackageType.single.id

        user.reload
        user.stripe_customer_id.should_not be nil
        user.lesson_purchases.length.should eql 1
        user.remaining_test_drives.should eql 0
        lesson_purchase = user.lesson_purchases[0]
        lesson_purchase.price.should eql 30.00
        lesson_purchase.lesson_package_type.is_normal?.should eql true

        customer = Stripe::Customer.retrieve(user.stripe_customer_id)
        customer.email.should eql user.email

        sale.sale_line_items.count.should eql 1
        line_item = sale.sale_line_items[0]
        line_item.reload
        line_item.affiliate_distributions.count.should eql 0
      end

      it "affiliate" do
        user.affiliate_referral = affiliate_partner
        user.save!
        teacher_user.affiliate_referral = affiliate_partner2
        teacher_user.save!

        token = create_stripe_token
        result = user.payment_update({token: token, zip: '78759', normal: true})

        lesson_session = normal_lesson(user, teacher_user)

        # teacher & student get into session
        start = lesson_session.scheduled_start
        end_time = lesson_session.scheduled_start + (60 * lesson_session.duration)
        uh2 = FactoryGirl.create(:music_session_user_history, user: teacher_user, history: lesson_session.music_session, created_at: start, session_removed_at: end_time)
        # artificially end the session, which is covered by other background jobs
        lesson_session.music_session.session_removed_at = end_time
        lesson_session.music_session.save!

        Timecop.travel(end_time + 1)

        # bill the user
        LessonSession.hourly_check

        lesson_session.reload
        payment = lesson_session.lesson_payment_charge
        puts lesson_session.billing_error_reason
        puts lesson_session.billing_error_detail
        user.reload
        user.sales.count.should eql 1
        sale = user.sales.first
        sale.stripe_charge_id.should_not be_nil
        sale.recurly_tax_in_cents.should be 248
        sale.recurly_total_in_cents.should eql 3248
        sale.recurly_subtotal_in_cents.should eql 3000
        sale.recurly_currency.should eql 'USD'
        line_item = sale.sale_line_items[0]
        line_item.quantity.should eql 1
        line_item.product_type.should eql SaleLineItem::LESSON
        line_item.product_id.should eq LessonPackageType.single.id

        user.reload
        user.stripe_customer_id.should_not be nil
        user.lesson_purchases.length.should eql 1
        user.remaining_test_drives.should eql 0
        lesson_purchase = user.lesson_purchases[0]
        lesson_purchase.price.should eql 30.00
        lesson_purchase.lesson_package_type.is_normal?.should eql true

        customer = Stripe::Customer.retrieve(user.stripe_customer_id)
        customer.email.should eql user.email

        sale.sale_line_items.count.should eql 1
        line_item = sale.sale_line_items[0]
        line_item.reload
        line_item.affiliate_distributions.count.should eql 2
        affiliate_partner.reload
        affiliate_partner2.reload
        affiliate_partner.affiliate_distributions.count.should eql 1
        affiliate_partner2.affiliate_distributions.count.should eql 1
        partner1_distribution = affiliate_partner.affiliate_distributions.first
        partner2_distribution = affiliate_partner2.affiliate_distributions.first
        partner1_distribution.sale_line_item.should eql partner2_distribution.sale_line_item
        partner1_distribution.affiliate_referral_fee_in_cents.should eql (3000 * 0.25 * affiliate_partner.lesson_rate).round
        partner2_distribution.affiliate_referral_fee_in_cents.should eql (3000 * 0.25 * affiliate_partner2.lesson_rate).round
      end

      it "book recurring, monthly" do

      end

    end
    describe "purchase_test_drive" do
      it "can succeed" do
        user.affiliate_referral = affiliate_partner
        user.save!
        teacher_user.affiliate_referral = affiliate_partner2
        teacher_user.save!


        booking = LessonBooking.book_test_drive(user, teacher_user, valid_single_slots, "Hey I've heard of you before.")
        booking.errors.any?.should be_false
        booking.user.should eql user
        booking.card_presumed_ok.should be_false
        booking.should eql user.unprocessed_test_drive

        token = create_stripe_token
        result = user.payment_update({token: token, zip: '72205', test_drive: true, booking_id: booking.id})

        booking.reload
        booking.card_presumed_ok.should be_true

        user.sales.count.should eql 1
        sale = result[:test_drive]

        sale.stripe_charge_id.should_not be_nil
        sale.recurly_tax_in_cents.should be 0
        sale.recurly_total_in_cents.should eql 4999
        sale.recurly_subtotal_in_cents.should eql 4999
        sale.recurly_currency.should eql 'USD'
        line_item = sale.sale_line_items[0]
        line_item.quantity.should eql 1
        line_item.product_type.should eql SaleLineItem::LESSON
        line_item.product_id.should eq LessonPackageType.test_drive_4.id

        user.reload
        user.stripe_customer_id.should_not be nil
        user.lesson_purchases.length.should eql 1
        user.remaining_test_drives.should eql 3
        lesson_purchase = user.lesson_purchases[0]
        lesson_purchase.price.should eql 49.99
        lesson_purchase.lesson_package_type.is_test_drive?.should eql true

        customer = Stripe::Customer.retrieve(user.stripe_customer_id)
        customer.email.should eql user.email

        sale.sale_line_items.count.should eql 1
        line_item = sale.sale_line_items[0]
        line_item.reload
        line_item.affiliate_distributions.count.should eql 0 # test drives don't create affiliate
      end

      it "can succeed with tax" do
        #user.remaining_test_drives = 0
        #user.save!
        booking = LessonBooking.book_test_drive(user, teacher_user, valid_single_slots, "Hey I've heard of you before.")
        booking.errors.any?.should be_false
        booking.user.should eql user
        booking.card_presumed_ok.should be_false
        booking.should eql user.unprocessed_test_drive
        user.reload
        user.remaining_test_drives.should eql 0

        token = create_stripe_token
        result = user.payment_update({token: token, zip: '78759', test_drive: true, booking_id: booking.id})

        booking.reload
        booking.card_presumed_ok.should be_true

        user.sales.count.should eql 1
        sale = result[:test_drive]

        sale.stripe_charge_id.should_not be_nil
        sale.recurly_tax_in_cents.should be (4999 * 0.0825).round
        sale.recurly_total_in_cents.should eql 4999 + (4999 * 0.0825).round
        sale.recurly_subtotal_in_cents.should eql 4999
        sale.recurly_currency.should eql 'USD'
        line_item = sale.sale_line_items[0]
        line_item.quantity.should eql 1
        line_item.product_type.should eql SaleLineItem::LESSON
        line_item.product_id.should eq LessonPackageType.test_drive_4.id


        user.reload
        user.stripe_customer_id.should_not be nil
        user.lesson_purchases.length.should eql 1
        lesson_purchase = booking.lesson_sessions[0].lesson_package_purchase
        user.remaining_test_drives.should eql 3
        lesson_purchase = user.lesson_purchases[0]
        lesson_purchase.price.should eql 49.99
        lesson_purchase.lesson_package_type.is_test_drive?.should eql true

        customer = Stripe::Customer.retrieve(user.stripe_customer_id)
        customer.email.should eql user.email

        booking.lesson_sessions[0].accept({message: "got it", slot: booking.lesson_booking_slots[0].id})
        user.reload
        user.remaining_test_drives.should eql 3
        line_item.affiliate_distributions.count.should eql 0 # test drives don't create affiliate
      end

      it "can succeed with no booking; just intent" do
        user.desired_package = LessonPackageType.test_drive_4
        intent = TeacherIntent.create(user, teacher, 'book-test-drive')
        token = create_stripe_token
        result = user.payment_update({token: token, zip: '78759', test_drive: true})

        user.errors.any?.should be_false
        user.reload
        user.has_stored_credit_card?.should be_true

        user.sales.count.should eql  1
        sale = result[:test_drive]

        sale.stripe_charge_id.should_not be_nil
        sale.recurly_tax_in_cents.should be (4999 * 0.0825).round
        sale.recurly_total_in_cents.should eql 4999 + (4999 * 0.0825).round
        sale.recurly_subtotal_in_cents.should eql 4999
        sale.recurly_currency.should eql 'USD'
        line_item = sale.sale_line_items[0]
        line_item.quantity.should eql 1
        line_item.product_type.should eql SaleLineItem::LESSON
        line_item.product_id.should eq LessonPackageType.test_drive_4.id
      end

      it "will reject second test drive purchase" do
        user.desired_package = LessonPackageType.test_drive_4
        intent = TeacherIntent.create(user, teacher, 'book-test-drive')
        token = create_stripe_token
        result = user.payment_update({token: token, zip: '78759', test_drive: true})
        user.errors.any?.should be_false
        user.reload
        user.has_stored_credit_card?.should be_true
        user.sales.count.should eql 1
        SaleLineItem.count.should eql 1
        Sale.count.should eql 1
        purchase = result[:purchase]
        purchase.errors.any?.should be_false

        result = user.payment_update({token: token, zip: '78759', test_drive: true})
        user.errors.any?.should be_false
        user.reload
        user.has_stored_credit_card?.should be_true
        user.sales.count.should eql 1
        purchase = result[:purchase]
        purchase.errors.any?.should be_true
        purchase.errors[:user].should eq ["can not buy test drive right now because you have already purchased it within the last year"]
        SaleLineItem.count.should eql 1
        Sale.count.should eql 1


      end
    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
      check_integrity = Sale.check_integrity_of_jam_track_sales
      check_integrity.length.should eq(1)
      r = check_integrity[0]
      r.total.to_i.should eq(0)
      r.voided.to_i.should eq(0)
    end

    it "one succeeded sale" do
      sale = Sale.create_jam_track_sale(user)
      shopping_cart = ShoppingCart.create(user, jam_track)
      SaleLineItem.create_from_shopping_cart(sale, shopping_cart, nil, 'some_recurly_invoice_id', nil)

      check_integrity = Sale.check_integrity_of_jam_track_sales
      r = check_integrity[0]
      r.total.to_i.should eq(1)
      r.voided.to_i.should eq(0)
    end


    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.total.to_i.should eq(1)
      r.voided.to_i.should eq(1)
    end


  end
end

