=begin
require 'spec_helper'

describe "Normal Lesson Flow" do

  let(:user) { FactoryGirl.create(:user, remaining_test_drives: 0) }

  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) }
  let(:school) {FactoryGirl.create(:school)}
  let(:retailer) {FactoryGirl.create(:retailer)}

  after {Timecop.return}

  describe "stripe mocked" do
    before {
      StripeMock.clear_errors
      StripeMock.start
      teacher.stripe_account_id = stripe_account1_id
      teacher.save!
    }
    after { StripeMock.stop }

    it "bill failure" do

      # user has no test drives, no credit card on file, but attempts to book a lesson
      booking = LessonBooking.book_normal(user, teacher_user, valid_single_slots, "Hey I've heard of you before.", false, LessonBooking::PAYMENT_STYLE_SINGLE, 60)
      booking.errors.any?.should be_false
      booking.card_presumed_ok.should be_false
      booking.user.should eql user
      booking.card_presumed_ok.should be_false
      booking.should eql user.unprocessed_normal_lesson
      booking.sent_notices.should be_false
      booking.booked_price.should eql 30.00

      ##########  Need validate their credit card
      token = create_stripe_token
      result = user.payment_update({token: token, zip: '78759', normal: true, booking_id: booking.id})
      booking = result[:lesson]
      lesson = booking.lesson_sessions[0]
      booking.errors.any?.should be_false
      lesson.errors.any?.should be_false
      booking.card_presumed_ok.should be_true
      booking.sent_notices.should be_true
      lesson.music_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)
      lesson.amount_charged.should be 0.0
      lesson.reload

      user.reload
      user.stripe_customer_id.should_not be nil
      user.remaining_test_drives.should eql 0
      user.lesson_purchases.length.should eql 0

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

      booking.lesson_sessions.length.should eql 1
      lesson_session = booking.lesson_sessions[0]
      lesson_session.status.should eql LessonBooking::STATUS_REQUESTED
      booking.status.should eql LessonBooking::STATUS_REQUESTED

      ######## Teacher accepts slot
      UserMailer.deliveries.clear

      lesson_session.accept({message: 'Yeah I got this', slot: booking.default_slot.id, update_all: false, accepter: teacher_user})
      lesson_session.errors.any?.should be_false
      lesson_session.reload
      lesson_session.slot.should eql booking.default_slot
      lesson_session.status.should eql LessonSession::STATUS_APPROVED
      booking.reload
      lesson_session.music_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)
      booking.status.should eql LessonBooking::STATUS_APPROVED

      UserMailer.deliveries.length.should eql 2
      chat = ChatMessage.unscoped.order(:created_at).last
      chat.message.should eql 'Yeah I got this'
      chat.purpose.should eql 'Lesson Approved'
      chat.channel.should eql ChatMessage::CHANNEL_LESSON
      chat.user.should eql teacher_user
      chat.target_user.should eql user
      notification = Notification.unscoped.order(:created_at).last
      notification.session_id.should eql lesson_session.music_session.id
      notification.student_directed.should eql true
      notification.purpose.should eql 'accept'
      notification.description.should eql NotificationTypes::LESSON_MESSAGE

      # 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)

      UserMailer.deliveries.clear
      # background code comes around and analyses the session

      StripeMock.prepare_card_error(:card_declined)

      lesson_session.lesson_payment_charge.billing_attempts.should eql 0
      user.lesson_purchases.length.should eql 0
      LessonSession.hourly_check
      lesson_session.reload
      lesson_session.analysed.should be_true
      analysis = lesson_session.analysis
      analysis["reason"].should eql LessonSessionAnalyser::STUDENT_FAULT
      analysis["student"].should eql LessonSessionAnalyser::NO_SHOW
      lesson_session.billing_attempts.should eql 1
      lesson_session.billing_error_reason.should eql 'card_declined'
      lesson_session.billed.should eql false
      lesson_session.billing_attempts.should eql 1
      user.reload
      user.lesson_purchases.length.should eql 0

      LessonBooking.hourly_check

      lesson_session.reload
      teacher_distribution = lesson_session.teacher_distribution
      teacher_distribution.amount_in_cents.should eql 3000
      teacher_distribution.ready.should be_false
      teacher_distribution.distributed.should be_false


      # let's reattempt right away; this should have no effect because we only try to bill once per 24 hours

      LessonSession.hourly_check
      lesson_session.reload
      lesson_session.analysed.should be_true
      analysis = lesson_session.analysis
      analysis["reason"].should eql LessonSessionAnalyser::STUDENT_FAULT
      analysis["student"].should eql LessonSessionAnalyser::NO_SHOW
      lesson_session.billing_error_reason.should eql 'card_declined'
      lesson_session.billed.should eql false
      lesson_session.billing_attempts.should eql 1
      user.reload
      user.lesson_purchases.length.should eql 0

      Timecop.freeze((24 + 1).hours.from_now)
      StripeMock.clear_errors
      StripeMock.prepare_card_error(:expired_card)

      LessonSession.hourly_check
      lesson_session.reload
      lesson_session.analysed.should be_true
      analysis = lesson_session.analysis
      analysis["reason"].should eql LessonSessionAnalyser::STUDENT_FAULT
      analysis["student"].should eql LessonSessionAnalyser::NO_SHOW
      lesson_session.billing_attempts.should eql 2
      lesson_session.billing_error_reason.should eql 'card_expired'
      lesson_session.billed.should eql false
      user.reload
      user.lesson_purchases.length.should eql 0

      Timecop.freeze((24 + 24 + 2).hours.from_now)
      StripeMock.clear_errors
      StripeMock.prepare_card_error(:processing_error)

      LessonSession.hourly_check
      lesson_session.reload
      lesson_session.analysed.should be_true
      analysis = lesson_session.analysis
      analysis["reason"].should eql LessonSessionAnalyser::STUDENT_FAULT
      analysis["student"].should eql LessonSessionAnalyser::NO_SHOW
      lesson_session.billing_attempts.should eql 3
      lesson_session.billing_error_reason.should eql 'processing_error'
      lesson_session.billed.should eql false
      user.reload
      user.lesson_purchases.length.should eql 0


      Timecop.freeze((24 + 24 + 24 + 3).hours.from_now)
      StripeMock.clear_errors

      UserMailer.deliveries.clear

      # finally the user will get billed!
      LessonSession.hourly_check


      lesson_session.reload
      payment = lesson_session.lesson_payment_charge
      payment.amount_in_cents.should eql 3248
      payment.fee_in_cents.should eql 0

      lesson_session.billing_attempts.should eql 4
      lesson_session.post_processed.should be_true
      LessonPaymentCharge.count.should eql 1

      lesson_session.reload
      lesson_session.analysed.should be_true
      analysis = lesson_session.analysis
      analysis["reason"].should eql LessonSessionAnalyser::STUDENT_FAULT
      analysis["student"].should eql LessonSessionAnalyser::NO_SHOW
      lesson_session.billing_attempts.should eql 4
      if lesson_session.billing_error_detail
        lesson_session.billing_error_detail
      end
      lesson_session.billing_error_reason.should eql 'processing_error'
      lesson_session.billed.should eql true
      user.reload
      user.lesson_purchases.length.should eql 1

      LessonBooking.hourly_check
      payment.reload
      payment.amount_in_cents.should eql 3248
      payment.fee_in_cents.should eql 0
      lesson_session.reload
      teacher_distribution = lesson_session.teacher_distribution
      teacher_distribution.amount_in_cents.should eql 3000
      teacher_distribution.ready.should be_true
      teacher_distribution.distributed.should be_false
      lesson_purchase = user.lesson_purchases[0]
      lesson_purchase.price.should eql 30.00
      lesson_purchase.lesson_package_type.is_normal?.should eql true
      lesson_purchase.price_in_cents.should eql 3000
      user.sales.length.should eql 1
      sale = user.sales.first
      sale.stripe_charge_id.should_not be_nil
      sale.recurly_tax_in_cents.should eql (100 * booking.booked_price.to_f * 0.0825).round.to_i
      sale.recurly_total_in_cents.should eql ((100 * booking.booked_price.to_f * 0.0825).round + 100 * booking.booked_price.to_f).to_i
      sale.recurly_subtotal_in_cents.should eql (100 * booking.booked_price).to_i
      sale.recurly_currency.should eql 'USD'
      sale.stripe_charge_id.should_not be_nil
      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
      line_item.lesson_package_purchase.should eql lesson_purchase
      lesson_purchase.sale_line_item.should eql line_item
      lesson.reload
      lesson.amount_charged.should eql (sale.recurly_total_in_cents / 100.0).to_f
      lesson_session.billing_error_reason.should eql 'processing_error'
      lesson_session.sent_billing_notices.should be true
      user.reload
      user.remaining_test_drives.should eql 0
      UserMailer.deliveries.length.should eql 2 # one for student, one for teacher

      TeacherPayment.count.should eql 0
      TeacherPayment.hourly_check
      TeacherPayment.count.should eql 1
      teacher_distribution.reload
      teacher_distribution.distributed.should be_true

      payment = TeacherPayment.first
      payment.amount_in_cents.should eql 3000
      payment.fee_in_cents.should eql (3000 * 0.28).round
      payment.teacher_payment_charge.amount_in_cents.should eql ((3000 * 0.72) + (3000 * 0.72) * APP_CONFIG.stripe[:ach_pct]).round
      payment.teacher_payment_charge.fee_in_cents.should eql (3000 * 0.28).round
      payment.teacher.should eql teacher_user
      payment.teacher_distribution.should eql teacher_distribution
      lesson_session.lesson_booking.status.should eql LessonBooking::STATUS_COMPLETED
      lesson_session.lesson_booking.success.should be_true
      lesson_session.teacher.has_booked_test_drive_with_student?(user).should be_false

    end
  end


  it "works" do

    # set up teacher stripe acct
    teacher.stripe_account_id = stripe_account1_id

    # user has no test drives, no credit card on file, but attempts to book a lesson
    booking = LessonBooking.book_normal(user, teacher_user, valid_single_slots, "Hey I've heard of you before.", false, LessonBooking::PAYMENT_STYLE_SINGLE, 60)
    booking.errors.any?.should be_false
    booking.card_presumed_ok.should be_false
    booking.user.should eql user
    booking.card_presumed_ok.should be_false
    booking.same_school_free.should be_false
    booking.should eql user.unprocessed_normal_lesson
    booking.sent_notices.should be_false
    booking.booked_price.should eql 30.00

    ##########  Need validate their credit card
    token = create_stripe_token
    result = user.payment_update({token: token, zip: '78759', normal: true, booking_id: booking.id})
    booking = result[:lesson]
    lesson = booking.lesson_sessions[0]
    booking.errors.any?.should be_false
    lesson.errors.any?.should be_false
    booking.card_presumed_ok.should be_true
    booking.sent_notices.should be_true
    lesson.music_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)
    lesson.amount_charged.should eql 0.0
    lesson.reload

    user.reload
    user.stripe_customer_id.should_not be nil
    user.remaining_test_drives.should eql 0
    user.lesson_purchases.length.should eql 0
    teacher_user.stripe_auth.should_not be_nil

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

    booking.lesson_sessions.length.should eql 1
    lesson_session = booking.lesson_sessions[0]
    lesson_session.status.should eql LessonBooking::STATUS_REQUESTED
    booking.status.should eql LessonBooking::STATUS_REQUESTED

    ######### Teacher counters with new slot
    teacher_countered_slot = FactoryGirl.build(:lesson_booking_slot_single, hour: 14)
    UserMailer.deliveries.clear
    lesson_session.counter({proposer: teacher_user, slot: teacher_countered_slot, message: 'Does this work?'})
    booking.reload
    booking.errors.any?.should be false
    lesson_session.lesson_booking.errors.any?.should be false
    lesson_session.lesson_booking_slots.length.should eql 1
    lesson_session.lesson_booking_slots[0].proposer.should eql teacher_user
    teacher_counter = lesson_session.lesson_booking_slots.order(:created_at).last
    teacher_counter.should eql teacher_countered_slot
    teacher_counter.proposer.should eql teacher_user
    #lesson_session.lesson_booking_slots.length.should eql 3
    UserMailer.deliveries.length.should eql 1
    chat = ChatMessage.unscoped.order(:created_at).last
    chat.channel.should eql ChatMessage::CHANNEL_LESSON
    chat.message.should eql 'Does this work?'
    chat.user.should eql teacher_user
    chat.target_user.should eql user
    notification = Notification.unscoped.order(:created_at).last
    notification.session_id.should eql lesson_session.music_session.id
    notification.student_directed.should eql true
    notification.purpose.should eql 'counter'
    notification.description.should eql NotificationTypes::LESSON_MESSAGE

    ######### Student counters with new slot
    student_countered_slot = FactoryGirl.build(:lesson_booking_slot_single, hour: 16)
    UserMailer.deliveries.clear
    lesson_session.counter({proposer: user, slot: student_countered_slot, message: 'Does this work better?'})
    lesson_session.errors.any?.should be false
    lesson_session.lesson_booking.errors.any?.should be false
    lesson_session.lesson_booking_slots.length.should eql 2
    student_counter = booking.lesson_booking_slots.order(:created_at).last
    student_counter.proposer.should eql user
    booking.reload
    #booking.lesson_booking_slots.length.should eql 4
    UserMailer.deliveries.length.should eql 1
    chat = ChatMessage.unscoped.order(:created_at).last
    chat.message.should eql 'Does this work better?'
    chat.channel.should eql ChatMessage::CHANNEL_LESSON
    chat.user.should eql user
    chat.target_user.should eql teacher_user
    notification = Notification.unscoped.order(:created_at).last
    notification.session_id.should eql lesson_session.music_session.id
    notification.student_directed.should eql false
    notification.purpose.should eql 'counter'
    notification.description.should eql NotificationTypes::LESSON_MESSAGE

    ######## Teacher accepts slot
    UserMailer.deliveries.clear

    lesson_session.accept({message: 'Yeah I got this', slot: student_counter.id, update_all: false,accepter: teacher_user})
    lesson_session.errors.any?.should be_false
    lesson_session.reload
    lesson_session.slot.should eql student_counter
    lesson_session.status.should eql LessonSession::STATUS_APPROVED
    booking.reload
    booking.default_slot.should eql student_counter
    lesson_session.music_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)
    booking.status.should eql LessonBooking::STATUS_APPROVED

    UserMailer.deliveries.length.should eql 2
    chat = ChatMessage.unscoped.order(:created_at).last
    chat.message.should eql 'Yeah I got this'
    chat.purpose.should eql 'Lesson Approved'
    chat.channel.should eql ChatMessage::CHANNEL_LESSON
    chat.user.should eql teacher_user
    chat.target_user.should eql user
    notification = Notification.unscoped.order(:created_at).last
    notification.session_id.should eql lesson_session.music_session.id
    notification.student_directed.should eql true
    notification.purpose.should eql 'accept'
    notification.description.should eql NotificationTypes::LESSON_MESSAGE

    # 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)

    UserMailer.deliveries.clear
    # background code comes around and analyses the session
    LessonSession.hourly_check

    lesson_session.reload
    lesson_session.analysed.should be_true
    analysis = lesson_session.analysis
    analysis["reason"].should eql LessonSessionAnalyser::STUDENT_FAULT
    analysis["student"].should eql LessonSessionAnalyser::NO_SHOW
    if lesson_session.billing_error_detail
      puts "testdrive flow #{lesson_session.billing_error_detail}" # this should not occur, but helps a great deal if a regression occurs and running all the tests
    end

    TeacherPayment.count.should eql 0
    TeacherPayment.hourly_check
    TeacherPayment.count.should eql 1


    teacher_distribution = lesson_session.teacher_distribution
    teacher_distribution.ready.should be_true
    teacher_distribution.distributed.should be_true
    education_distribution = lesson_session.education_distribution
    education_distribution.should be_nil
    lesson_session.billed.should be true
    user.reload
    user.lesson_purchases.length.should eql 1
    lesson_purchase = user.lesson_purchases[0]
    lesson_purchase.price.should eql 30.00
    lesson_purchase.lesson_package_type.is_normal?.should eql true
    lesson_purchase.price_in_cents.should eql 3000
    user.sales.length.should eql 1
    sale = user.sales.first
    sale.stripe_charge_id.should_not be_nil
    sale.recurly_tax_in_cents.should eql (100 * booking.booked_price.to_f * 0.0825).round.to_i
    sale.recurly_total_in_cents.should eql ((100 * booking.booked_price.to_f * 0.0825).round + 100 * booking.booked_price.to_f).to_i
    sale.recurly_subtotal_in_cents.should eql (100 * booking.booked_price).to_i
    sale.recurly_currency.should eql 'USD'
    sale.stripe_charge_id.should_not be_nil
    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
    line_item.lesson_package_purchase.should eql lesson_purchase
    lesson_purchase.sale_line_item.should eql line_item
    lesson.amount_charged.should eql (sale.recurly_total_in_cents / 100.0).to_f
    lesson_session.billing_error_reason.should be_nil
    lesson_session.sent_billing_notices.should be true
    user.reload
    user.remaining_test_drives.should eql 0
    UserMailer.deliveries.length.should eql 3 # one for student, one for teacher
  end

  it "works (school on school guitarcenter)" do

    gc = GuitarCenter.init
    gc_owner = gc[:user]
    gc_school = gc[:school]
    gc_retailer = gc[:retailer]


    # make sure teacher can get payments
    teacher.stripe_account_id = stripe_account1_id
    gc_school.user.stripe_account_id = stripe_account2_id

    # make sure can get stripe payments

    # get user and teacher into same school

    gc_school.save!
    user.school = gc_school
    user.save!
    teacher.school = gc_school
    teacher.save!

    # user has no test drives, no credit card on file, but attempts to book a lesson
    booking = LessonBooking.book_normal(user, teacher_user, valid_single_slots, "Hey I've heard of you before.", false, LessonBooking::PAYMENT_STYLE_SINGLE, 60)
    booking.errors.any?.should be_false
    booking.school.should be_true
    booking.card_presumed_ok.should be_false
    booking.user.should eql user
    booking.same_school_free.should be_false
    #user.unprocessed_normal_lesson.should be_nil
    booking.sent_notices.should be_false
    booking.booked_price.should eql 30.00
    booking.is_requested?.should be_true
    booking.lesson_sessions[0].music_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)
    LessonPaymentCharge.count.should eql 1


    ##########  Need validate their credit card
    token = create_stripe_token
    result = user.payment_update({token: token, zip: '78759', normal: true, booking_id: booking.id})
    booking = result[:lesson]
    lesson = booking.lesson_sessions[0]
    booking.errors.any?.should be_false
    lesson.errors.any?.should be_false
    booking.card_presumed_ok.should be_true
    booking.sent_notices.should be_true
    booking.school.is_guitar_center?.should be_true
    lesson.music_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)
    lesson.amount_charged.should eql 0.0
    lesson.reload

    user.reload
    user.stripe_customer_id.should_not be nil
    user.remaining_test_drives.should eql 0
    user.lesson_purchases.length.should eql 0

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

    booking.lesson_sessions.length.should eql 1
    lesson_session = booking.lesson_sessions[0]
    lesson_session.status.should eql LessonBooking::STATUS_REQUESTED
    booking.status.should eql LessonBooking::STATUS_REQUESTED

    ######### Teacher counters with new slot
    teacher_countered_slot = FactoryGirl.build(:lesson_booking_slot_single, hour: 14)
    UserMailer.deliveries.clear
    lesson_session.counter({proposer: teacher_user, slot: teacher_countered_slot, message: 'Does this work?'})
    booking.reload
    booking.errors.any?.should be false
    lesson_session.lesson_booking.errors.any?.should be false
    lesson_session.lesson_booking_slots.length.should eql 1
    lesson_session.lesson_booking_slots[0].proposer.should eql teacher_user
    teacher_counter = lesson_session.lesson_booking_slots.order(:created_at).last
    teacher_counter.should eql teacher_countered_slot
    teacher_counter.proposer.should eql teacher_user
    #booking.lesson_sessions.lesson_booking_slots.length.should eql 3
    UserMailer.deliveries.length.should eql 1
    chat = ChatMessage.unscoped.order(:created_at).last
    chat.channel.should eql ChatMessage::CHANNEL_LESSON
    chat.message.should eql 'Does this work?'
    chat.user.should eql teacher_user
    chat.target_user.should eql user
    notification = Notification.unscoped.order(:created_at).last
    notification.session_id.should eql lesson_session.music_session.id
    notification.student_directed.should eql true
    notification.purpose.should eql 'counter'
    notification.description.should eql NotificationTypes::LESSON_MESSAGE

    ######### Student counters with new slot
    student_countered_slot = FactoryGirl.build(:lesson_booking_slot_single, hour: 16)
    UserMailer.deliveries.clear
    lesson_session.counter({proposer: user, slot: student_countered_slot, message: 'Does this work better?'})
    lesson_session.errors.any?.should be false
    lesson_session.lesson_booking.errors.any?.should be false
    lesson_session.lesson_booking_slots.length.should eql 2
    student_counter = booking.lesson_booking_slots.order(:created_at).last
    student_counter.proposer.should eql user
    booking.reload
    #booking.lesson_booking_slots.length.should eql 4
    UserMailer.deliveries.length.should eql 1
    chat = ChatMessage.unscoped.order(:created_at).last
    chat.message.should eql 'Does this work better?'
    chat.channel.should eql ChatMessage::CHANNEL_LESSON
    chat.user.should eql user
    chat.target_user.should eql teacher_user
    notification = Notification.unscoped.order(:created_at).last
    notification.session_id.should eql lesson_session.music_session.id
    notification.student_directed.should eql false
    notification.purpose.should eql 'counter'
    notification.description.should eql NotificationTypes::LESSON_MESSAGE

    ######## Teacher accepts slot
    UserMailer.deliveries.clear

    lesson_session.accept({message: 'Yeah I got this', slot: student_counter.id, update_all: false, accepter: teacher_user})
    lesson_session.errors.any?.should be_false
    lesson_session.reload
    lesson_session.slot.should eql student_counter
    lesson_session.status.should eql LessonSession::STATUS_APPROVED
    booking.reload
    booking.default_slot.should eql student_counter
    lesson_session.music_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)
    booking.status.should eql LessonBooking::STATUS_APPROVED

    UserMailer.deliveries.length.should eql 2
    chat = ChatMessage.unscoped.order(:created_at).last
    chat.message.should eql 'Yeah I got this'
    chat.purpose.should eql 'Lesson Approved'
    chat.channel.should eql ChatMessage::CHANNEL_LESSON
    chat.user.should eql teacher_user
    chat.target_user.should eql user
    notification = Notification.unscoped.order(:created_at).last
    notification.session_id.should eql lesson_session.music_session.id
    notification.student_directed.should eql true
    notification.purpose.should eql 'accept'
    notification.description.should eql NotificationTypes::LESSON_MESSAGE

    # 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)

    UserMailer.deliveries.clear
    # background code comes around and analyses the session
    LessonSession.hourly_check
    lesson_session.reload
    lesson_session.analysed.should be_true
    analysis = lesson_session.analysis
    analysis["reason"].should eql LessonSessionAnalyser::STUDENT_FAULT
    analysis["student"].should eql LessonSessionAnalyser::NO_SHOW
    lesson_session.billed.should be_true
    if lesson_session.billing_error_detail
      puts "testdrive flow #{lesson_session.billing_error_detail}" # this should not occur, but helps a great deal if a regression occurs and running all the tests
    end
    lesson_session.billing_attempts.should eql 1
    user.reload
    user.lesson_purchases.length.should eql 1

    LessonBooking.hourly_check

    lesson_session.reload
    teacher_distribution = lesson_session.teacher_distribution
    teacher_distribution.amount_in_cents.should eql 3000
    teacher_distribution.ready.should be_true
    teacher_distribution.distributed.should be_false

    lesson_session.teacher_distributions.count.should eql 1
    education_distribution = lesson_session.education_distribution
    education_distribution.should be_nil

    lesson_session.billed.should be true
    user.reload
    user.lesson_purchases.length.should eql 1
    user.sales.length.should eql 1
    lesson_session.amount_charged.should eql 32.48
    lesson_session.billing_error_reason.should be_nil
    lesson_session.sent_billing_notices.should be_true
    user.reload
    user.remaining_test_drives.should eql 0
    UserMailer.deliveries.length.should eql 2 # one for student, one for teacher

    TeacherPayment.count.should eql 0
    TeacherPayment.hourly_check
    TeacherPayment.count.should eql 1

    LessonPaymentCharge.count.should eql 1
    TeacherDistribution.count.should eql 1

    teacher_distribution.reload
    teacher_distribution.distributed.should be_true

    payment = teacher_distribution.teacher_payment
    payment.amount_in_cents.should eql 3000
    payment.fee_in_cents.should eql (3000 * (gc_school.base_rate +  0.03)).round
    payment.teacher_payment_charge.amount_in_cents.should eql ((teacher_distribution.amount_in_cents - teacher_distribution.teacher_fee_in_cents) + (teacher_distribution.amount_in_cents - teacher_distribution.teacher_fee_in_cents)  * APP_CONFIG.stripe[:ach_pct]).round
    payment.teacher_payment_charge.fee_in_cents.should eql payment.teacher_payment_charge.fee_in_cents
    payment.teacher.should eql teacher_user
    payment.teacher_distribution.should eql teacher_distribution
    lesson_session.lesson_booking.status.should eql LessonBooking::STATUS_COMPLETED
    lesson_session.lesson_booking.success.should be_true
  end



  it "works (school on school only)" do

    # make sure teacher can get payments
    teacher.stripe_account_id = stripe_account1_id
    school.user.stripe_account_id = stripe_account2_id

    # make sure can get stripe payments

    # get user and teacher into same school

    school.save!
    user.school = school
    user.save!
    teacher.school = school
    teacher.save!

    # user has no test drives, no credit card on file, but attempts to book a lesson
    booking = LessonBooking.book_normal(user, teacher_user, valid_single_slots, "Hey I've heard of you before.", false, LessonBooking::PAYMENT_STYLE_SINGLE, 60)
    booking.errors.any?.should be_false
    booking.school.should be_true
    booking.card_presumed_ok.should be_false
    booking.user.should eql user
    booking.same_school_free.should be_false
    #user.unprocessed_normal_lesson.should be_nil
    booking.sent_notices.should be_false
    booking.booked_price.should eql 30.00
    booking.is_requested?.should be_true
    booking.lesson_sessions[0].music_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)
    LessonPaymentCharge.count.should eql 1


    ##########  Need validate their credit card
    token = create_stripe_token
    result = user.payment_update({token: token, zip: '78759', normal: true, booking_id: booking.id})
    booking = result[:lesson]
    lesson = booking.lesson_sessions[0]
    booking.errors.any?.should be_false
    lesson.errors.any?.should be_false
    booking.card_presumed_ok.should be_true
    booking.sent_notices.should be_true
    lesson.music_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)
    lesson.amount_charged.should eql 0.0
    lesson.reload

    user.reload
    user.stripe_customer_id.should_not be nil
    user.remaining_test_drives.should eql 0
    user.lesson_purchases.length.should eql 0

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

    booking.lesson_sessions.length.should eql 1
    lesson_session = booking.lesson_sessions[0]
    lesson_session.status.should eql LessonBooking::STATUS_REQUESTED
    booking.status.should eql LessonBooking::STATUS_REQUESTED

    ######### Teacher counters with new slot
    teacher_countered_slot = FactoryGirl.build(:lesson_booking_slot_single, hour: 14)
    UserMailer.deliveries.clear
    lesson_session.counter({proposer: teacher_user, slot: teacher_countered_slot, message: 'Does this work?'})
    booking.reload
    booking.errors.any?.should be false
    lesson_session.lesson_booking.errors.any?.should be false
    lesson_session.lesson_booking_slots.length.should eql 1
    lesson_session.lesson_booking_slots[0].proposer.should eql teacher_user
    teacher_counter = lesson_session.lesson_booking_slots.order(:created_at).last
    teacher_counter.should eql teacher_countered_slot
    teacher_counter.proposer.should eql teacher_user
    #lesson_session.lesson_booking_slots.length.should eql 3
    UserMailer.deliveries.length.should eql 1
    chat = ChatMessage.unscoped.order(:created_at).last
    chat.channel.should eql ChatMessage::CHANNEL_LESSON
    chat.message.should eql 'Does this work?'
    chat.user.should eql teacher_user
    chat.target_user.should eql user
    notification = Notification.unscoped.order(:created_at).last
    notification.session_id.should eql lesson_session.music_session.id
    notification.student_directed.should eql true
    notification.purpose.should eql 'counter'
    notification.description.should eql NotificationTypes::LESSON_MESSAGE

    ######### Student counters with new slot
    student_countered_slot = FactoryGirl.build(:lesson_booking_slot_single, hour: 16)
    UserMailer.deliveries.clear
    lesson_session.counter({proposer: user, slot: student_countered_slot, message: 'Does this work better?'})
    lesson_session.errors.any?.should be false
    lesson_session.lesson_booking.errors.any?.should be false
    lesson_session.lesson_booking_slots.length.should eql 2
    student_counter = booking.lesson_booking_slots.order(:created_at).last
    student_counter.proposer.should eql user
    booking.reload
    #booking.lesson_booking_slots.length.should eql 4
    UserMailer.deliveries.length.should eql 1
    chat = ChatMessage.unscoped.order(:created_at).last
    chat.message.should eql 'Does this work better?'
    chat.channel.should eql ChatMessage::CHANNEL_LESSON
    chat.user.should eql user
    chat.target_user.should eql teacher_user
    notification = Notification.unscoped.order(:created_at).last
    notification.session_id.should eql lesson_session.music_session.id
    notification.student_directed.should eql false
    notification.purpose.should eql 'counter'
    notification.description.should eql NotificationTypes::LESSON_MESSAGE

    ######## Teacher accepts slot
    UserMailer.deliveries.clear

    lesson_session.accept({message: 'Yeah I got this', slot: student_counter.id, update_all: false, accepter: teacher_user})
    lesson_session.errors.any?.should be_false
    lesson_session.reload
    lesson_session.slot.should eql student_counter
    lesson_session.status.should eql LessonSession::STATUS_APPROVED
    booking.reload
    booking.default_slot.should eql student_counter
    lesson_session.music_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)
    booking.status.should eql LessonBooking::STATUS_APPROVED

    UserMailer.deliveries.length.should eql 2
    chat = ChatMessage.unscoped.order(:created_at).last
    chat.message.should eql 'Yeah I got this'
    chat.purpose.should eql 'Lesson Approved'
    chat.channel.should eql ChatMessage::CHANNEL_LESSON
    chat.user.should eql teacher_user
    chat.target_user.should eql user
    notification = Notification.unscoped.order(:created_at).last
    notification.session_id.should eql lesson_session.music_session.id
    notification.student_directed.should eql true
    notification.purpose.should eql 'accept'
    notification.description.should eql NotificationTypes::LESSON_MESSAGE

    # 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)

    UserMailer.deliveries.clear
    # background code comes around and analyses the session
    LessonSession.hourly_check
    lesson_session.reload
    lesson_session.analysed.should be_true
    analysis = lesson_session.analysis
    analysis["reason"].should eql LessonSessionAnalyser::STUDENT_FAULT
    analysis["student"].should eql LessonSessionAnalyser::NO_SHOW
    lesson_session.billed.should be_true
    if lesson_session.billing_error_detail
      puts "testdrive flow #{lesson_session.billing_error_detail}" # this should not occur, but helps a great deal if a regression occurs and running all the tests
    end
    lesson_session.billing_attempts.should eql 1
    user.reload
    user.lesson_purchases.length.should eql 1

    LessonBooking.hourly_check

    lesson_session.reload
    teacher_distribution = lesson_session.teacher_distribution
    teacher_distribution.amount_in_cents.should eql 3000
    teacher_distribution.ready.should be_true
    teacher_distribution.distributed.should be_false

    lesson_session.teacher_distributions.count.should eql 1
    education_distribution = lesson_session.education_distribution
    education_distribution.should be_nil

    lesson_session.billed.should be true
    user.reload
    user.lesson_purchases.length.should eql 1
    user.sales.length.should eql 1
    lesson_session.amount_charged.should eql 32.48
    lesson_session.billing_error_reason.should be_nil
    lesson_session.sent_billing_notices.should be_true
    user.reload
    user.remaining_test_drives.should eql 0
    UserMailer.deliveries.length.should eql 2 # one for student, one for teacher

    TeacherPayment.count.should eql 0
    TeacherPayment.hourly_check
    TeacherPayment.count.should eql 1

    LessonPaymentCharge.count.should eql 1
    TeacherDistribution.count.should eql 1

    teacher_distribution.reload
    teacher_distribution.distributed.should be_false

    payment = teacher_distribution.teacher_payment
    payment.amount_in_cents.should eql 3000
    payment.fee_in_cents.should eql (3000 * (school.base_rate + 0.03)).round
    payment.teacher_payment_charge.amount_in_cents.should eql ((teacher_distribution.amount_in_cents - teacher_distribution.teacher_fee_in_cents) + (teacher_distribution.amount_in_cents - teacher_distribution.teacher_fee_in_cents)  * APP_CONFIG.stripe[:ach_pct]).round
    payment.teacher_payment_charge.fee_in_cents.should eql payment.teacher_payment_charge.fee_in_cents
    payment.teacher.should eql teacher_user
    payment.teacher_distribution.should eql teacher_distribution
    lesson_session.lesson_booking.status.should eql LessonBooking::STATUS_COMPLETED
    lesson_session.lesson_booking.success.should be_true
  end


  it "works (school on school education)" do

    # make sure teacher can get payments
    teacher.stripe_account_id = stripe_account1_id
    school.user.stripe_account_id = stripe_account2_id

    # make sure can get stripe payments

    # get user and teacher into same school

    school.education = true
    school.save!
    user.school = school
    user.save!
    teacher.school = school
    teacher.save!

    # user has no test drives, no credit card on file, but attempts to book a lesson
    booking = LessonBooking.book_normal(user, teacher_user, valid_single_slots, "Hey I've heard of you before.", false, LessonBooking::PAYMENT_STYLE_SINGLE, 60)
    booking.errors.any?.should be_false
    booking.school.should be_true
    booking.card_presumed_ok.should be_false
    booking.user.should eql user
    booking.same_school_free.should be_false
    #user.unprocessed_normal_lesson.should be_nil
    booking.sent_notices.should be_false
    booking.booked_price.should eql 30.00
    booking.is_requested?.should be_true
    booking.lesson_sessions[0].music_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)
    LessonPaymentCharge.count.should eql 1


    ##########  Need validate their credit card
    token = create_stripe_token
    result = user.payment_update({token: token, zip: '78759', normal: true, booking_id: booking.id})
    booking = result[:lesson]
    lesson = booking.lesson_sessions[0]
    booking.errors.any?.should be_false
    lesson.errors.any?.should be_false
    booking.card_presumed_ok.should be_true
    booking.sent_notices.should be_true
    lesson.music_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)
    lesson.amount_charged.should eql 0.0
    lesson.reload

    user.reload
    user.stripe_customer_id.should_not be nil
    user.remaining_test_drives.should eql 0
    user.lesson_purchases.length.should eql 0

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

    booking.lesson_sessions.length.should eql 1
    lesson_session = booking.lesson_sessions[0]
    lesson_session.status.should eql LessonBooking::STATUS_REQUESTED
    booking.status.should eql LessonBooking::STATUS_REQUESTED

    ######### Teacher counters with new slot
    teacher_countered_slot = FactoryGirl.build(:lesson_booking_slot_single, hour: 14)
    UserMailer.deliveries.clear
    lesson_session.counter({proposer: teacher_user, slot: teacher_countered_slot, message: 'Does this work?'})
    booking.reload
    booking.errors.any?.should be false
    lesson_session.lesson_booking.errors.any?.should be false
    lesson_session.lesson_booking_slots.length.should eql 1
    lesson_session.lesson_booking_slots[0].proposer.should eql teacher_user
    teacher_counter = lesson_session.lesson_booking_slots.order(:created_at).last
    teacher_counter.should eql teacher_countered_slot
    teacher_counter.proposer.should eql teacher_user
    #lesson_session.lesson_booking_slots.length.should eql 3
    UserMailer.deliveries.length.should eql 1
    chat = ChatMessage.unscoped.order(:created_at).last
    chat.channel.should eql ChatMessage::CHANNEL_LESSON
    chat.message.should eql 'Does this work?'
    chat.user.should eql teacher_user
    chat.target_user.should eql user
    notification = Notification.unscoped.order(:created_at).last
    notification.session_id.should eql lesson_session.music_session.id
    notification.student_directed.should eql true
    notification.purpose.should eql 'counter'
    notification.description.should eql NotificationTypes::LESSON_MESSAGE

    ######### Student counters with new slot
    student_countered_slot = FactoryGirl.build(:lesson_booking_slot_single, hour: 16)
    UserMailer.deliveries.clear
    lesson_session.counter({proposer: user, slot: student_countered_slot, message: 'Does this work better?'})
    lesson_session.errors.any?.should be false
    lesson_session.lesson_booking.errors.any?.should be false
    lesson_session.lesson_booking_slots.length.should eql 2
    student_counter = booking.lesson_booking_slots.order(:created_at).last
    student_counter.proposer.should eql user
    booking.reload
    #booking.lesson_booking_slots.length.should eql 4
    UserMailer.deliveries.length.should eql 1
    chat = ChatMessage.unscoped.order(:created_at).last
    chat.message.should eql 'Does this work better?'
    chat.channel.should eql ChatMessage::CHANNEL_LESSON
    chat.user.should eql user
    chat.target_user.should eql teacher_user
    notification = Notification.unscoped.order(:created_at).last
    notification.session_id.should eql lesson_session.music_session.id
    notification.student_directed.should eql false
    notification.purpose.should eql 'counter'
    notification.description.should eql NotificationTypes::LESSON_MESSAGE

    ######## Teacher accepts slot
    UserMailer.deliveries.clear

    lesson_session.accept({message: 'Yeah I got this', slot: student_counter.id, update_all: false, accepter: teacher_user})
    lesson_session.errors.any?.should be_false
    lesson_session.reload
    lesson_session.slot.should eql student_counter
    lesson_session.status.should eql LessonSession::STATUS_APPROVED
    booking.reload
    booking.default_slot.should eql student_counter
    lesson_session.music_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)
    booking.status.should eql LessonBooking::STATUS_APPROVED

    UserMailer.deliveries.length.should eql 2
    chat = ChatMessage.unscoped.order(:created_at).last
    chat.message.should eql 'Yeah I got this'
    chat.purpose.should eql 'Lesson Approved'
    chat.channel.should eql ChatMessage::CHANNEL_LESSON
    chat.user.should eql teacher_user
    chat.target_user.should eql user
    notification = Notification.unscoped.order(:created_at).last
    notification.session_id.should eql lesson_session.music_session.id
    notification.student_directed.should eql true
    notification.purpose.should eql 'accept'
    notification.description.should eql NotificationTypes::LESSON_MESSAGE

    # 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)

    UserMailer.deliveries.clear
    # background code comes around and analyses the session
    LessonSession.hourly_check
    lesson_session.reload
    lesson_session.analysed.should be_true
    analysis = lesson_session.analysis
    analysis["reason"].should eql LessonSessionAnalyser::STUDENT_FAULT
    analysis["student"].should eql LessonSessionAnalyser::NO_SHOW
    lesson_session.billed.should be_true
    if lesson_session.billing_error_detail
      puts "testdrive flow #{lesson_session.billing_error_detail}" # this should not occur, but helps a great deal if a regression occurs and running all the tests
    end
    lesson_session.billing_attempts.should eql 1
    user.reload
    user.lesson_purchases.length.should eql 1

    LessonBooking.hourly_check

    lesson_session.reload
    teacher_distribution = lesson_session.teacher_distribution
    teacher_distribution.amount_in_cents.should eql 3000
    teacher_distribution.ready.should be_true
    teacher_distribution.distributed.should be_false

    lesson_session.teacher_distributions.count.should eql 2
    education_distribution = lesson_session.education_distribution
    education_distribution.amount_in_cents.should eql (3000 * 0.0625).round
    education_distribution.ready.should be_true
    education_distribution.distributed.should be_false

    lesson_session.billed.should be true
    user.reload
    user.lesson_purchases.length.should eql 1
    user.sales.length.should eql 1
    lesson_session.amount_charged.should eql 32.48
    lesson_session.billing_error_reason.should be_nil
    lesson_session.sent_billing_notices.should be_true
    user.reload
    user.remaining_test_drives.should eql 0
    UserMailer.deliveries.length.should eql 2 # one for student, one for teacher

    TeacherPayment.count.should eql 0
    TeacherPayment.hourly_check
    TeacherPayment.count.should eql 2

    LessonPaymentCharge.count.should eql 1
    TeacherDistribution.count.should eql 2


    teacher_distribution.reload
    teacher_distribution.distributed.should be_true
    education_distribution.reload
    education_distribution.distributed.should be_true

    education_amt =  (3000 * 0.0625).round
    payment = education_distribution.teacher_payment
    payment.amount_in_cents.should eql education_amt
    payment.fee_in_cents.should eql 0
    payment.teacher_payment_charge.amount_in_cents.should eql (education_amt + education_amt * APP_CONFIG.stripe[:ach_pct]).round
    payment.teacher_payment_charge.fee_in_cents.should eql 0
    payment.teacher.should eql teacher_user
    payment.teacher_distribution.should eql education_distribution
    payment = teacher_distribution.teacher_payment
    payment.amount_in_cents.should eql 3000
    payment.fee_in_cents.should eql (3000 * (school.base_rate + 0.03)).round
    payment.teacher_payment_charge.amount_in_cents.should eql ((teacher_distribution.amount_in_cents - teacher_distribution.teacher_fee_in_cents) + (teacher_distribution.amount_in_cents - teacher_distribution.teacher_fee_in_cents)  * APP_CONFIG.stripe[:ach_pct]).round
    payment.teacher_payment_charge.fee_in_cents.should eql payment.teacher_payment_charge.fee_in_cents
    payment.teacher.should eql teacher_user
    payment.teacher_distribution.should eql teacher_distribution
    lesson_session.lesson_booking.status.should eql LessonBooking::STATUS_COMPLETED
    lesson_session.lesson_booking.success.should be_true
  end

  it "works (retailer on retailer)" do

    # make sure teacher can get payments
    teacher.stripe_account_id = stripe_account1_id
    retailer.user.stripe_account_id = stripe_account2_id

    # make sure can get stripe payments

    # get user and teacher into same retailer

    teacher_split = 70
    retailer_split = 30
    teacher_split_pct = (teacher_split / 100.0)
    retailer_split_pct = (retailer_split / 100.0)
    retailer.update_payment({teacher: teacher_split, retailer:retailer_split})
    retailer.save!

    user.affiliate_referral = retailer.affiliate_partner
    user.save!
    teacher.retailer = retailer
    teacher.save!

    # user has no test drives, no credit card on file, but attempts to book a lesson
    booking = LessonBooking.book_normal(user, teacher_user, valid_single_slots, "Hey I've heard of you before.", false, LessonBooking::PAYMENT_STYLE_SINGLE, 60)
    booking.errors.any?.should be_false
    booking.retailer.should eql retailer
    booking.card_presumed_ok.should be_false
    booking.user.should eql user
    booking.same_school_free.should be_false
    booking.same_retailer.should be_true
    #user.unprocessed_normal_lesson.should be_nil
    booking.sent_notices.should be_false
    booking.booked_price.should eql 30.00
    booking.is_requested?.should be_true
    booking.lesson_sessions[0].music_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)
    LessonPaymentCharge.count.should eql 1


    ##########  Need validate their credit card
    token = create_stripe_token
    result = user.payment_update({token: token, zip: '78759', normal: true, booking_id: booking.id})
    booking = result[:lesson]
    lesson = booking.lesson_sessions[0]
    booking.errors.any?.should be_false
    lesson.errors.any?.should be_false
    booking.card_presumed_ok.should be_true
    booking.sent_notices.should be_true
    lesson.music_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)
    lesson.amount_charged.should eql 0.0
    lesson.reload

    user.reload
    user.stripe_customer_id.should_not be nil
    user.remaining_test_drives.should eql 0
    user.lesson_purchases.length.should eql 0

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

    booking.lesson_sessions.length.should eql 1
    lesson_session = booking.lesson_sessions[0]
    lesson_session.status.should eql LessonBooking::STATUS_REQUESTED
    booking.status.should eql LessonBooking::STATUS_REQUESTED

    ######### Teacher counters with new slot
    teacher_countered_slot = FactoryGirl.build(:lesson_booking_slot_single, hour: 14)
    UserMailer.deliveries.clear
    lesson_session.counter({proposer: teacher_user, slot: teacher_countered_slot, message: 'Does this work?'})
    booking.reload
    booking.errors.any?.should be false
    lesson_session.lesson_booking.errors.any?.should be false
    lesson_session.lesson_booking_slots.length.should eql 1
    lesson_session.lesson_booking_slots[0].proposer.should eql teacher_user
    teacher_counter = lesson_session.lesson_booking_slots.order(:created_at).last
    teacher_counter.should eql teacher_countered_slot
    teacher_counter.proposer.should eql teacher_user
    #lesson_session.lesson_booking_slots.length.should eql 3
    UserMailer.deliveries.length.should eql 1
    chat = ChatMessage.unscoped.order(:created_at).last
    chat.channel.should eql ChatMessage::CHANNEL_LESSON
    chat.message.should eql 'Does this work?'
    chat.user.should eql teacher_user
    chat.target_user.should eql user
    notification = Notification.unscoped.order(:created_at).last
    notification.session_id.should eql lesson_session.music_session.id
    notification.student_directed.should eql true
    notification.purpose.should eql 'counter'
    notification.description.should eql NotificationTypes::LESSON_MESSAGE

    ######### Student counters with new slot
    student_countered_slot = FactoryGirl.build(:lesson_booking_slot_single, hour: 16)
    UserMailer.deliveries.clear
    lesson_session.counter({proposer: user, slot: student_countered_slot, message: 'Does this work better?'})
    lesson_session.errors.any?.should be false
    lesson_session.lesson_booking.errors.any?.should be false
    lesson_session.lesson_booking_slots.length.should eql 2
    student_counter = booking.lesson_booking_slots.order(:created_at).last
    student_counter.proposer.should eql user
    booking.reload
    #booking.lesson_booking_slots.length.should eql 4
    UserMailer.deliveries.length.should eql 1
    chat = ChatMessage.unscoped.order(:created_at).last
    chat.message.should eql 'Does this work better?'
    chat.channel.should eql ChatMessage::CHANNEL_LESSON
    chat.user.should eql user
    chat.target_user.should eql teacher_user
    notification = Notification.unscoped.order(:created_at).last
    notification.session_id.should eql lesson_session.music_session.id
    notification.student_directed.should eql false
    notification.purpose.should eql 'counter'
    notification.description.should eql NotificationTypes::LESSON_MESSAGE

    ######## Teacher accepts slot
    UserMailer.deliveries.clear

    lesson_session.accept({message: 'Yeah I got this', slot: student_counter.id, update_all: false, accepter: teacher_user})
    lesson_session.errors.any?.should be_false
    lesson_session.reload
    lesson_session.slot.should eql student_counter
    lesson_session.status.should eql LessonSession::STATUS_APPROVED
    booking.reload
    booking.default_slot.should eql student_counter
    lesson_session.music_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)
    booking.status.should eql LessonBooking::STATUS_APPROVED

    UserMailer.deliveries.length.should eql 2
    chat = ChatMessage.unscoped.order(:created_at).last
    chat.message.should eql 'Yeah I got this'
    chat.purpose.should eql 'Lesson Approved'
    chat.channel.should eql ChatMessage::CHANNEL_LESSON
    chat.user.should eql teacher_user
    chat.target_user.should eql user
    notification = Notification.unscoped.order(:created_at).last
    notification.session_id.should eql lesson_session.music_session.id
    notification.student_directed.should eql true
    notification.purpose.should eql 'accept'
    notification.description.should eql NotificationTypes::LESSON_MESSAGE

    # 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)

    UserMailer.deliveries.clear
    # background code comes around and analyses the session
    LessonSession.hourly_check
    lesson_session.reload
    lesson_session.analysed.should be_true
    analysis = lesson_session.analysis
    analysis["reason"].should eql LessonSessionAnalyser::STUDENT_FAULT
    analysis["student"].should eql LessonSessionAnalyser::NO_SHOW
    lesson_session.billed.should be_true
    if lesson_session.billing_error_detail
      puts "testdrive flow #{lesson_session.billing_error_detail}" # this should not occur, but helps a great deal if a regression occurs and running all the tests
    end
    lesson_session.billing_attempts.should eql 1
    user.reload
    user.lesson_purchases.length.should eql 1

    LessonBooking.hourly_check

    lesson_session.reload
    lesson_session.education_distribution.should be_nil
    teacher_distribution = lesson_session.teacher_distribution
    teacher_distribution.amount_in_cents.should eql (3000 * teacher_split_pct).round
    teacher_distribution.teacher_fee_in_cents.should eql (teacher_distribution.amount_in_cents * (teacher_split_pct * (retailer.jamkazam_rate + APP_CONFIG.stripe[:charge_fee]))).round
    teacher_distribution.ready.should be_true
    teacher_distribution.distributed.should be_false

    lesson_session.teacher_distributions.count.should eql 2
    retailer_distribution = lesson_session.retailer_distribution
    retailer_distribution.amount_in_cents.should eql (3000 * retailer_split_pct).round
    retailer_distribution.teacher_fee_in_cents.should eql (retailer_distribution.amount_in_cents * (retailer_split_pct * (retailer.jamkazam_rate + APP_CONFIG.stripe[:charge_fee]))).round
    retailer_distribution.ready.should be_true
    retailer_distribution.distributed.should be_false

    lesson_session.billed.should be true
    user.reload
    user.lesson_purchases.length.should eql 1
    user.sales.length.should eql 1
    lesson_session.amount_charged.should eql 32.48
    lesson_session.billing_error_reason.should be_nil
    lesson_session.sent_billing_notices.should be_true
    user.reload
    user.remaining_test_drives.should eql 0
    UserMailer.deliveries.length.should eql 2 # one for student, one for teacher

    TeacherPayment.count.should eql 0
    TeacherPayment.hourly_check
    TeacherPayment.count.should eql 2

    LessonPaymentCharge.count.should eql 1
    TeacherDistribution.count.should eql 2


    teacher_distribution.reload
    teacher_distribution.distributed.should be_true
    retailer_distribution.reload
    retailer_distribution.distributed.should be_true

    retailer_amt =  (3000 * retailer_split_pct).round
    payment = retailer_distribution.teacher_payment
    payment.amount_in_cents.should eql retailer_distribution.amount_in_cents
    payment.fee_in_cents.should eql retailer_distribution.teacher_fee_in_cents
    payment.teacher_payment_charge.amount_in_cents.should eql ((retailer_distribution.amount_in_cents - retailer_distribution.teacher_fee_in_cents) + (retailer_distribution.amount_in_cents - retailer_distribution.teacher_fee_in_cents)  * APP_CONFIG.stripe[:ach_pct]).round
    payment.teacher_payment_charge.fee_in_cents.should eql  retailer_distribution.teacher_fee_in_cents
    payment.teacher.should eql teacher_user
    payment.teacher_distribution.should eql retailer_distribution
    payment = teacher_distribution.teacher_payment
    payment.amount_in_cents.should eql teacher_distribution.amount_in_cents
    payment.fee_in_cents.should eql teacher_distribution.teacher_fee_in_cents
    payment.teacher_payment_charge.amount_in_cents.should eql ((teacher_distribution.amount_in_cents - teacher_distribution.teacher_fee_in_cents) + (teacher_distribution.amount_in_cents - teacher_distribution.teacher_fee_in_cents)  * APP_CONFIG.stripe[:ach_pct]).round
    payment.teacher_payment_charge.fee_in_cents.should eql payment.teacher_payment_charge.fee_in_cents
    payment.teacher.should eql teacher_user
    payment.teacher_distribution.should eql teacher_distribution
    lesson_session.lesson_booking.status.should eql LessonBooking::STATUS_COMPLETED
    lesson_session.lesson_booking.success.should be_true
  end

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

    lesson = normal_lesson(user, teacher_user, {accept: true, finish:true})

    user.reload
    user.sales.count.should eql 1
    user.sales[0].sale_line_items[0].affiliate_distributions.count.should eql 2
    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 "school affiliate gets nothing when teacher school is involved" do
    teacher.school = school
    teacher.save!

    user.affiliate_referral = affiliate_partner
    user.save!

    lesson = normal_lesson(user, teacher_user, {accept: true, finish:true})
    lesson.errors.any?.should be_false

    user.sales.count.should eql 1
    user.sales[0].sale_line_items[0].affiliate_distributions.count.should eql 1

    affiliate_partner.affiliate_distributions.count.should eql 1
    partner1_distribution = affiliate_partner.affiliate_distributions.first
    partner1_distribution.affiliate_referral_fee_in_cents.should eql (3000 * 0.30 * affiliate_partner.lesson_rate).round
    school.affiliate_partner.affiliate_distributions.count.should eql 0
  end

  it "student school affiliates gets cut when student school is involved. so does teacher's" do
    user.affiliate_referral = school.affiliate_partner
    user.save!

    teacher_user.affiliate_referral = affiliate_partner
    teacher_user.save!

    lesson = normal_lesson(user, teacher_user, {accept: true, finish:true})

    user.sales.count.should eql 1
    user.sales[0].sale_line_items[0].affiliate_distributions.count.should eql 2

    affiliate_partner.affiliate_distributions.count.should eql 1
    affiliate_partner.affiliate_distributions.count.should eql 1
    partner1_distribution = affiliate_partner.affiliate_distributions.first
    partner1_distribution.affiliate_referral_fee_in_cents.should eql (3000 * 0.25 * affiliate_partner.lesson_rate).round
    school.affiliate_partner.affiliate_distributions.count.should eql 1
    school_partner_distribution = school.affiliate_partner.affiliate_distributions.first
    school_partner_distribution.affiliate_referral_fee_in_cents.should eql (3000 * 0.25 * school.affiliate_partner.lesson_rate).round
  end
end
=end