859 lines
36 KiB
Ruby
859 lines
36 KiB
Ruby
require 'spec_helper'
|
|
|
|
# collissions with teacher's schedule?
|
|
describe LessonBooking do
|
|
|
|
let(:user) { FactoryGirl.create(:user, stored_credit_card: false, remaining_free_lessons: 1, remaining_test_drives: 1) }
|
|
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] }
|
|
|
|
describe "suspend!" do
|
|
it "should set status as well as update status of all associated lesson_sessions" do
|
|
booking = LessonBooking.book_normal(user, teacher_user, valid_recurring_slots, "Hey I've heard of you before.", true, LessonBooking::PAYMENT_STYLE_MONTHLY, 60)
|
|
booking.lesson_sessions[0].accept({accepter: teacher_user, message: "got it", slot: booking.lesson_booking_slots[0].id})
|
|
booking.reload
|
|
booking.active.should eql true
|
|
booking.suspend!
|
|
booking.errors.any?.should be false
|
|
booking.reload
|
|
booking.active.should eql false
|
|
booking.status.should eql LessonBooking::STATUS_SUSPENDED
|
|
booking.lesson_sessions.count.should eql 2
|
|
booking.lesson_sessions.each do |lesson_session|
|
|
lesson_session.status.should eql LessonBooking::STATUS_SUSPENDED
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "bill_monthlies" do
|
|
after do
|
|
Timecop.return
|
|
end
|
|
|
|
it "empty" do
|
|
LessonBooking.count.should eql 0
|
|
LessonBooking.bill_monthlies
|
|
LessonPackagePurchase.count.should eql 0
|
|
end
|
|
|
|
it "one" do
|
|
day = Date.new(2016, 1, 1)
|
|
time = day.to_time
|
|
Timecop.freeze(time)
|
|
booking = LessonBooking.book_normal(user, teacher_user, valid_recurring_slots, "Hey I've heard of you before.", true, LessonBooking::PAYMENT_STYLE_MONTHLY, 60)
|
|
booking.accept(booking.lesson_sessions[0], booking.lesson_booking_slots[0], teacher_user)
|
|
booking.errors.any?.should be false
|
|
|
|
LessonBooking.count.should eql 1
|
|
LessonPackagePurchase.count.should eql 0
|
|
LessonBooking.bill_monthlies
|
|
LessonPackagePurchase.count.should eql 1
|
|
|
|
purchase = LessonPackagePurchase.first
|
|
purchase.billing_error_reason.should eql "stripe"
|
|
purchase.billing_error_detail.should include("Cannot charge a customer that has no active card")
|
|
purchase.month.should eql 1
|
|
purchase.year.should eql 2016
|
|
purchase.lesson_booking.should eql booking
|
|
purchase.teacher.should eql teacher_user
|
|
purchase.user.should eql user
|
|
purchase.billed.should eql false
|
|
purchase.billed_at.should be_nil
|
|
purchase.billing_attempts.should eql 1
|
|
purchase.post_processed.should eql false
|
|
purchase.post_processed_at.should be_nil
|
|
purchase.last_billing_attempt_at.should eql time
|
|
purchase.sent_billing_notices.should eql false
|
|
|
|
# don't advance time, but nothing should happen because last_billing time hasn't elapsed
|
|
LessonBooking.bill_monthlies
|
|
LessonPackagePurchase.count.should eql 1
|
|
purchase.reload
|
|
purchase.billing_error_reason.should eql "stripe"
|
|
purchase.billing_error_detail.should include("Cannot charge a customer that has no active card")
|
|
purchase.month.should eql 1
|
|
purchase.year.should eql 2016
|
|
purchase.lesson_booking.should eql booking
|
|
purchase.teacher.should eql teacher_user
|
|
purchase.user.should eql user
|
|
purchase.billed.should eql false
|
|
purchase.billed_at.should eql nil
|
|
purchase.billing_attempts.should eql 1
|
|
purchase.post_processed.should eql false
|
|
purchase.post_processed_at.should be_nil
|
|
purchase.last_billing_attempt_at.should eql time
|
|
purchase.sent_billing_notices.should eql false
|
|
|
|
day = day + 1
|
|
time = day.to_time
|
|
Timecop.freeze(time)
|
|
LessonBooking.bill_monthlies
|
|
LessonPackagePurchase.count.should eql 1
|
|
purchase.reload
|
|
|
|
purchase.billing_error_reason.should eql "stripe"
|
|
purchase.billing_error_detail.should include("Cannot charge a customer that has no active card")
|
|
purchase.month.should eql 1
|
|
purchase.year.should eql 2016
|
|
purchase.lesson_booking.should eql booking
|
|
purchase.teacher.should eql teacher_user
|
|
purchase.user.should eql user
|
|
purchase.billed.should eql false
|
|
purchase.billed_at.should eql nil
|
|
purchase.billing_attempts.should eql 2
|
|
purchase.post_processed.should eql false
|
|
purchase.post_processed_at.should be_nil
|
|
purchase.last_billing_attempt_at.should eql time
|
|
purchase.sent_billing_notices.should eql false
|
|
|
|
user.card_approved(create_stripe_token, '78759', booking.id)
|
|
user.save!
|
|
|
|
day = day + 1
|
|
time = day.to_time
|
|
Timecop.freeze(time)
|
|
LessonBooking.bill_monthlies
|
|
LessonPackagePurchase.count.should eql 1
|
|
purchase.reload
|
|
purchase.month.should eql 1
|
|
purchase.year.should eql 2016
|
|
purchase.lesson_booking.should eql booking
|
|
purchase.teacher.should eql teacher_user
|
|
purchase.user.should eql user
|
|
purchase.billed.should eql true
|
|
purchase.billed_at.should eql time
|
|
# purchase.billing_error_reason.should be nil
|
|
purchase.billing_attempts.should eql 3
|
|
purchase.post_processed.should eql true
|
|
purchase.post_processed_at.should eql time
|
|
purchase.last_billing_attempt_at.should eql time
|
|
purchase.sent_billing_notices.should eql true
|
|
end
|
|
|
|
it "advances to next month" do
|
|
user.card_approved(create_stripe_token, '78759', nil)
|
|
user.save!
|
|
|
|
day = Date.new(2016, 1, 20)
|
|
time = day.to_time
|
|
Timecop.freeze(time)
|
|
booking = LessonBooking.book_normal(user, teacher_user, valid_recurring_slots, "Hey I've heard of you before.", true, LessonBooking::PAYMENT_STYLE_MONTHLY, 60)
|
|
booking.accept(booking.lesson_sessions[0], booking.lesson_booking_slots[0], teacher_user)
|
|
booking.errors.any?.should be false
|
|
|
|
LessonBooking.count.should eql 1
|
|
LessonPackagePurchase.count.should eql 0
|
|
LessonBooking.bill_monthlies
|
|
LessonPackagePurchase.count.should eql 1
|
|
LessonSession.count.should eql 2
|
|
|
|
purchase = LessonPackagePurchase.first
|
|
purchase.month.should eql 1
|
|
purchase.year.should eql 2016
|
|
purchase.lesson_booking.should eql booking
|
|
purchase.teacher.should eql teacher_user
|
|
purchase.user.should eql user
|
|
purchase.billed.should eql true
|
|
purchase.billed_at.should eql time
|
|
# purchase.billing_error_reason.should be nil
|
|
purchase.billing_attempts.should eql 1
|
|
purchase.post_processed.should eql true
|
|
purchase.post_processed_at.should eql time
|
|
purchase.last_billing_attempt_at.should eql time
|
|
purchase.sent_billing_notices.should eql true
|
|
|
|
day = Date.new(2016, 1, 27)
|
|
time = day.to_time
|
|
Timecop.freeze(time)
|
|
|
|
LessonBooking.schedule_upcoming_lessons
|
|
LessonSession.count.should eql 3
|
|
LessonPackagePurchase.count.should eql 1
|
|
LessonBooking.bill_monthlies
|
|
LessonPackagePurchase.count.should eql 2
|
|
|
|
purchase = LessonPackagePurchase.order(:month).last
|
|
purchase.month.should eql 2
|
|
purchase.year.should eql 2016
|
|
purchase.lesson_booking.should eql booking
|
|
purchase.teacher.should eql teacher_user
|
|
purchase.user.should eql user
|
|
purchase.billed.should eql true
|
|
purchase.billed_at.should eql time
|
|
# purchase.billing_error_reason.should be nil
|
|
purchase.billing_attempts.should eql 1
|
|
purchase.post_processed.should eql true
|
|
purchase.post_processed_at.should eql time
|
|
purchase.last_billing_attempt_at.should eql time
|
|
purchase.sent_billing_notices.should eql true
|
|
end
|
|
|
|
it "will suspend after enough tries" do
|
|
day = Date.new(2016, 1, 1)
|
|
time = day.to_time
|
|
Timecop.freeze(time)
|
|
booking = LessonBooking.book_normal(user, teacher_user, valid_recurring_slots, "Hey I've heard of you before.", true, LessonBooking::PAYMENT_STYLE_MONTHLY, 60)
|
|
booking.accept(booking.lesson_sessions[0], booking.lesson_booking_slots[0], teacher_user)
|
|
booking.errors.any?.should be false
|
|
|
|
LessonBooking.count.should eql 1
|
|
LessonPackagePurchase.count.should eql 0
|
|
LessonBooking.bill_monthlies
|
|
LessonPackagePurchase.count.should eql 1
|
|
|
|
purchase = LessonPackagePurchase.first
|
|
purchase.billing_error_reason.should eql "stripe"
|
|
purchase.billing_error_detail.should include("Cannot charge a customer that has no active card")
|
|
purchase.billing_attempts.should eql 1
|
|
booking.is_suspended?.should be_false
|
|
purchase.billed.should be false
|
|
day = day + 1
|
|
time = day.to_time
|
|
Timecop.freeze(time)
|
|
LessonBooking.bill_monthlies
|
|
LessonPackagePurchase.count.should eql 1
|
|
purchase.reload
|
|
purchase.billing_attempts.should eql 2
|
|
booking.reload
|
|
booking.is_suspended?.should be_false
|
|
purchase.billed.should be false
|
|
|
|
day = day + 1
|
|
time = day.to_time
|
|
Timecop.freeze(time)
|
|
LessonBooking.bill_monthlies
|
|
LessonPackagePurchase.count.should eql 1
|
|
purchase.reload
|
|
purchase.billing_attempts.should eql 3
|
|
booking.reload
|
|
booking.is_suspended?.should be_false
|
|
purchase.billed.should be false
|
|
|
|
day = day + 1
|
|
time = day.to_time
|
|
Timecop.freeze(time)
|
|
LessonBooking.bill_monthlies
|
|
LessonPackagePurchase.count.should eql 1
|
|
purchase.reload
|
|
purchase.billing_attempts.should eql 4
|
|
booking.reload
|
|
booking.is_suspended?.should be_false
|
|
purchase.billed.should be false
|
|
|
|
day = day + 1
|
|
time = day.to_time
|
|
Timecop.freeze(time)
|
|
LessonBooking.bill_monthlies
|
|
LessonPackagePurchase.count.should eql 1
|
|
purchase.reload
|
|
purchase.billing_attempts.should eql 5
|
|
booking.reload
|
|
booking.is_suspended?.should be_true
|
|
purchase.billed.should be false
|
|
|
|
# now that it's suspended, let's unsuspend it
|
|
user.card_approved(create_stripe_token, '78759', booking.id)
|
|
user.save!
|
|
|
|
day = day + 1
|
|
time = day.to_time
|
|
Timecop.freeze(time)
|
|
purchase.bill_monthly(true)
|
|
LessonPackagePurchase.count.should eql 1
|
|
purchase.reload
|
|
|
|
purchase.month.should eql 1
|
|
purchase.year.should eql 2016
|
|
purchase.lesson_booking.should eql booking
|
|
purchase.teacher.should eql teacher_user
|
|
purchase.user.should eql user
|
|
purchase.billed.should eql true
|
|
purchase.billed_at.should eql time
|
|
# purchase.billing_error_reason.should be nil
|
|
purchase.billing_attempts.should eql 6
|
|
purchase.post_processed.should eql true
|
|
purchase.post_processed_at.should eql time
|
|
purchase.last_billing_attempt_at.should eql time
|
|
purchase.sent_billing_notices.should eql true
|
|
booking.reload
|
|
booking.is_suspended?.should be_false
|
|
end
|
|
|
|
it "missed meetings deduct on next month" do
|
|
# TODO. Discuss with David a little more
|
|
end
|
|
end
|
|
|
|
describe "billable_monthlies" do
|
|
before do
|
|
Timecop.return
|
|
end
|
|
|
|
it "empty" do
|
|
LessonBooking.billable_monthlies(Time.now).count.should eql 0
|
|
end
|
|
|
|
it "one" do
|
|
time = Date.new(2016, 1, 1)
|
|
Timecop.freeze(time)
|
|
booking = LessonBooking.book_normal(user, teacher_user, valid_recurring_slots, "Hey I've heard of you before.", true, LessonBooking::PAYMENT_STYLE_MONTHLY, 60)
|
|
booking.accept(booking.lesson_sessions[0], booking.lesson_booking_slots[0], teacher_user)
|
|
booking.errors.any?.should be false
|
|
|
|
now = Time.now
|
|
billables = LessonBooking.billable_monthlies(now)
|
|
billables.all.should eql [booking]
|
|
LessonPackagePurchase.where(lesson_booking_id: booking.id).count.should eql 0
|
|
# to make this billable monthly go away, we will need to create one LessonPackagePurchase; one for this month (because it's only one we have lessons in)
|
|
# and further, mark them both as post_processed
|
|
|
|
package = LessonPackagePurchase.create(user, booking, LessonPackageType.single, 2016, 1)
|
|
|
|
LessonBooking.billable_monthlies(now).count.should eql 1
|
|
|
|
package.post_processed = true
|
|
package.save!
|
|
|
|
LessonBooking.billable_monthlies(now).count.should eql 0
|
|
end
|
|
end
|
|
|
|
describe "predicted_times_for_month" do
|
|
after do
|
|
Timecop.return
|
|
end
|
|
it "fills up month" do
|
|
|
|
next_year = Time.now.year + 1
|
|
jan1 = Date.new(next_year, 1, 1)
|
|
jan31 = Date.new(next_year, 1, -1)
|
|
Timecop.freeze(jan1)
|
|
slot = valid_recurring_slots[0]
|
|
slot.day_of_week = jan1.wday
|
|
|
|
booking = LessonBooking.book_normal(user, teacher_user, valid_recurring_slots, "Hey I've heard of you before.", true, LessonBooking::PAYMENT_STYLE_WEEKLY, 60)
|
|
times = booking.predicted_times_for_month(next_year, 1)
|
|
times.length.should eql 5
|
|
times[0].to_date.should eql (jan1)
|
|
times[1].to_date.should eql (Date.new(next_year, 1, 8))
|
|
times[2].to_date.should eql (Date.new(next_year, 1, 15))
|
|
times[3].to_date.should eql (Date.new(next_year, 1, 22))
|
|
times[4].to_date.should eql (Date.new(next_year, 1, 29))
|
|
end
|
|
|
|
it "fills up partial month" do
|
|
next_year = Time.now.year + 1
|
|
jan1 = Date.new(next_year, 1, 1)
|
|
jan15 = Date.new(next_year, 1, 15)
|
|
jan31 = Date.new(next_year, 1, -1)
|
|
Timecop.freeze(jan15)
|
|
slot = valid_recurring_slots[0]
|
|
slot.day_of_week = jan1.wday
|
|
|
|
booking = LessonBooking.book_normal(user, teacher_user, valid_recurring_slots, "Hey I've heard of you before.", true, LessonBooking::PAYMENT_STYLE_WEEKLY, 60)
|
|
times = booking.predicted_times_for_month(next_year, 1)
|
|
times.length.should eql 3
|
|
times[0].to_date.should eql (Date.new(next_year, 1, 15))
|
|
times[1].to_date.should eql (Date.new(next_year, 1, 22))
|
|
times[2].to_date.should eql (Date.new(next_year, 1, 29))
|
|
end
|
|
|
|
it "let's assume JamKazam is messed up for a few weeks" do
|
|
next_year = Time.now.year + 1
|
|
jan1 = Date.new(next_year, 1, 1)
|
|
jan15 = Date.new(next_year, 1, 15)
|
|
jan31 = Date.new(next_year, 1, -1)
|
|
Timecop.freeze(jan1)
|
|
slot = valid_recurring_slots[0]
|
|
slot.day_of_week = jan1.wday
|
|
|
|
# book a session on jan1
|
|
booking = LessonBooking.book_normal(user, teacher_user, valid_recurring_slots, "Hey I've heard of you before.", true, LessonBooking::PAYMENT_STYLE_WEEKLY, 60)
|
|
|
|
# but don't run the computation of times per month for weeks
|
|
Timecop.freeze(Date.new(next_year, 1, 23))
|
|
times = booking.predicted_times_for_month(next_year, 1)
|
|
times.length.should eql 2
|
|
times[0].to_date.should eql (Date.new(next_year, 1, 1))
|
|
times[1].to_date.should eql (Date.new(next_year, 1, 29))
|
|
end
|
|
end
|
|
|
|
describe "book_free" do
|
|
|
|
it "allows long message to flow through chat" do
|
|
|
|
user.has_free_lessons?.should be_true
|
|
booking = LessonBooking.book_test_drive(user, teacher_user, valid_single_slots, Faker::Lorem.characters(10000))
|
|
|
|
booking.errors.any?.should be false
|
|
|
|
chat_message = ChatMessage.where(lesson_session_id: booking.next_lesson.id).first
|
|
chat_message.should_not be_nil
|
|
chat_message.message.should eq booking.description
|
|
end
|
|
|
|
it "prevents user without free lesson" do
|
|
|
|
pending "free not supported"
|
|
booking = LessonBooking.book_free(user, teacher_user, valid_single_slots, "Hey I've heard of you before.")
|
|
booking.errors.any?.should be false
|
|
|
|
ChatMessage.count.should eq 1
|
|
|
|
booking = LessonBooking.book_free(user, teacher_user, valid_single_slots, "Hey I've heard of you before.")
|
|
booking.errors.any?.should be true
|
|
booking.errors[:user].should eq ["have no remaining free lessons"]
|
|
|
|
ChatMessage.count.should eq 1
|
|
end
|
|
|
|
it "must have 2 lesson booking slots" do
|
|
|
|
booking = LessonBooking.book_test_drive(user, teacher_user, [], "Hey I've heard of you before.")
|
|
booking.errors.any?.should be true
|
|
booking.errors[:lesson_booking_slots].should eq ["must have two times specified"]
|
|
end
|
|
|
|
it "must have well-formed booking slots" do
|
|
bad_slot = FactoryGirl.build(:lesson_booking_slot_single, minute: nil)
|
|
booking = LessonBooking.book_free(user, teacher_user, [lesson_booking_slot_single1, bad_slot], "Hey I've heard of you before.")
|
|
booking.errors.any?.should be true
|
|
booking.errors[:lesson_booking_slots].should eq ["is invalid"]
|
|
bad_slot = booking.lesson_booking_slots[1]
|
|
bad_slot.errors[:minute].should eq ["is not a number"]
|
|
end
|
|
end
|
|
|
|
describe "book_test_drive" do
|
|
it "works" do
|
|
user.stored_credit_card = true
|
|
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 eq user
|
|
booking.teacher.should eq teacher_user
|
|
booking.description.should eq ("Hey I've heard of you before.")
|
|
booking.payment_style.should eq LessonBooking::PAYMENT_STYLE_ELSEWHERE
|
|
booking.recurring.should eq false
|
|
booking.lesson_length.should eq 30
|
|
booking.lesson_type.should eq LessonBooking::LESSON_TYPE_TEST_DRIVE
|
|
booking.lesson_booking_slots.length.should eq 2
|
|
|
|
chat_message = ChatMessage.where(lesson_session_id: booking.next_lesson.id).first
|
|
chat_message.should_not be_nil
|
|
chat_message.message.should eq booking.description
|
|
|
|
user.reload
|
|
user.remaining_free_lessons.should eq 1
|
|
user.remaining_test_drives.should eq 0
|
|
end
|
|
|
|
it "allows long message to flow through chat" do
|
|
booking = LessonBooking.book_test_drive(user, teacher_user, valid_single_slots, Faker::Lorem.characters(10000))
|
|
|
|
booking.errors.any?.should be false
|
|
|
|
chat_message = ChatMessage.where(lesson_session_id: booking.next_lesson.id).first
|
|
chat_message.should_not be_nil
|
|
chat_message.message.should eq booking.description
|
|
end
|
|
|
|
it "prevents user without remaining test drives" do
|
|
|
|
user.stored_credit_card = true
|
|
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
|
|
ChatMessage.count.should eq 1
|
|
user.reload
|
|
user.remaining_test_drives.should eql 0
|
|
|
|
booking = LessonBooking.book_test_drive(user, teacher_user, valid_single_slots, "Hey I've heard of you before.")
|
|
booking.errors.any?.should be true
|
|
booking.errors[:user].should eq ["have a requested TestDrive with this teacher"]
|
|
|
|
ChatMessage.count.should eq 1
|
|
end
|
|
|
|
|
|
it "must have well-formed booking slots" do
|
|
bad_slot = FactoryGirl.build(:lesson_booking_slot_single, minute: nil)
|
|
booking = LessonBooking.book_test_drive(user, teacher_user, [lesson_booking_slot_single1, bad_slot], "Hey I've heard of you before.")
|
|
booking.errors.any?.should be true
|
|
booking.errors[:lesson_booking_slots].should eq ["is invalid"]
|
|
bad_slot = booking.lesson_booking_slots[1]
|
|
bad_slot.errors[:minute].should eq ["is not a number"]
|
|
end
|
|
end
|
|
|
|
describe "book_normal" do
|
|
it "works" do
|
|
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.user.should eq user
|
|
booking.teacher.should eq teacher_user
|
|
booking.description.should eq ("Hey I've heard of you before.")
|
|
booking.payment_style.should eq LessonBooking::PAYMENT_STYLE_SINGLE
|
|
booking.recurring.should eq false
|
|
booking.lesson_length.should eq 60
|
|
booking.lesson_type.should eq LessonBooking::LESSON_TYPE_PAID
|
|
booking.lesson_booking_slots.length.should eq 2
|
|
|
|
chat_message = ChatMessage.where(lesson_session_id: booking.next_lesson.id).first
|
|
chat_message.should_not be_nil
|
|
chat_message.message.should eq booking.description
|
|
|
|
user.reload
|
|
user.remaining_free_lessons.should eq 1
|
|
user.remaining_test_drives.should eq 1
|
|
end
|
|
|
|
it "works with recurring slots" do
|
|
booking = LessonBooking.book_normal(user, teacher_user, valid_recurring_slots, "Hey I've heard of you before.", true, LessonBooking::PAYMENT_STYLE_WEEKLY, 60)
|
|
booking.errors.any?.should be false
|
|
booking.user.should eq user
|
|
booking.teacher.should eq teacher_user
|
|
booking.description.should eq ("Hey I've heard of you before.")
|
|
booking.payment_style.should eq LessonBooking::PAYMENT_STYLE_WEEKLY
|
|
booking.recurring.should eq true
|
|
booking.lesson_length.should eq 60
|
|
booking.lesson_type.should eq LessonBooking::LESSON_TYPE_PAID
|
|
booking.lesson_booking_slots.length.should eq 2
|
|
|
|
chat_message = ChatMessage.where(lesson_session_id: booking.next_lesson.id).first
|
|
chat_message.should_not be_nil
|
|
chat_message.message.should eq booking.description
|
|
|
|
user.reload
|
|
user.remaining_free_lessons.should eq 1
|
|
user.remaining_test_drives.should eq 1
|
|
end
|
|
|
|
it "allows long message to flow through chat" do
|
|
booking = LessonBooking.book_normal(user, teacher_user, valid_recurring_slots, Faker::Lorem.characters(10000), true, LessonBooking::PAYMENT_STYLE_WEEKLY, 60)
|
|
|
|
booking.errors.any?.should be false
|
|
|
|
chat_message = ChatMessage.where(lesson_session_id: booking.next_lesson.id).first
|
|
chat_message.should_not be_nil
|
|
chat_message.message.should eq booking.description
|
|
end
|
|
|
|
it "does not prevent user without remaining test drives" do
|
|
booking = LessonBooking.book_test_drive(user, teacher_user, valid_single_slots, "Hey I've heard of you before.")
|
|
booking.errors.any?.should be false
|
|
|
|
ChatMessage.count.should eq 1
|
|
|
|
booking = LessonBooking.book_normal(user, teacher_user, valid_recurring_slots, "Hey I've heard of you before.", true, LessonBooking::PAYMENT_STYLE_WEEKLY, 60)
|
|
|
|
booking.errors.any?.should be false
|
|
|
|
ChatMessage.count.should eq 2
|
|
end
|
|
|
|
it "does not prevents user without free lesson" do
|
|
|
|
booking = LessonBooking.book_free(user, teacher_user, valid_single_slots, "Hey I've heard of you before.")
|
|
booking.errors.any?.should be false
|
|
|
|
ChatMessage.count.should eq 1
|
|
|
|
booking = LessonBooking.book_normal(user, teacher_user, valid_recurring_slots, "Hey I've heard of you before.", true, LessonBooking::PAYMENT_STYLE_WEEKLY, 60)
|
|
booking.errors.any?.should be false
|
|
|
|
ChatMessage.count.should eq 2
|
|
end
|
|
|
|
it "does not prevent user without a stored credit card" do
|
|
user.stored_credit_card = false
|
|
user.save!
|
|
|
|
booking = LessonBooking.book_normal(user, teacher_user, valid_recurring_slots, "Hey I've heard of you before.", true, LessonBooking::PAYMENT_STYLE_WEEKLY, 60)
|
|
booking.errors.any?.should be false
|
|
booking.card_presumed_ok.should eq false
|
|
booking.sent_notices.should eq false
|
|
end
|
|
|
|
|
|
it "must have well-formed booking slots" do
|
|
bad_slot = FactoryGirl.build(:lesson_booking_slot_recurring, day_of_week: nil)
|
|
booking = LessonBooking.book_test_drive(user, teacher_user, [lesson_booking_slot_recurring1, bad_slot], "Hey I've heard of you before.")
|
|
booking.errors.any?.should be true
|
|
booking.errors[:lesson_booking_slots].should eq ["is invalid"]
|
|
bad_slot = booking.lesson_booking_slots[1]
|
|
bad_slot.errors[:day_of_week].should eq ["must be specified"]
|
|
end
|
|
end
|
|
|
|
describe "find_bookings_needing_sessions" do
|
|
after do
|
|
Timecop.return
|
|
end
|
|
it "can detect missing lesson and schedules it 1 week out" do
|
|
booking = LessonBooking.book_normal(user, teacher_user, valid_recurring_slots, "Hey I've heard of you before.", true, LessonBooking::PAYMENT_STYLE_WEEKLY, 60)
|
|
booking.lesson_sessions.length.should eql 1
|
|
|
|
booking.accept(booking.lesson_sessions[0], booking.lesson_booking_slots[0], teacher_user)
|
|
booking.errors.any?.should be false
|
|
booking.reload
|
|
booking.lesson_sessions.length.should eql 2
|
|
|
|
lesson_session = booking.lesson_sessions[0]
|
|
Timecop.freeze(lesson_session.music_session.scheduled_start)
|
|
|
|
# causes find_bookings_needing_sessions to re-run
|
|
booking.sync_lessons
|
|
booking.reload
|
|
booking.lesson_sessions.length.should eql 3
|
|
|
|
# check that all the times make sense
|
|
|
|
lesson1 = booking.lesson_sessions[0]
|
|
lesson2 = booking.lesson_sessions[1]
|
|
lesson3 = booking.lesson_sessions[2]
|
|
lesson1.music_session.scheduled_start.to_i.should eql (lesson2.music_session.scheduled_start.to_i - (60 * 60 * 24 * 7))
|
|
lesson1.music_session.scheduled_start.to_i.should eql (lesson3.music_session.scheduled_start.to_i - (60 * 60 * 24 * 14))
|
|
|
|
Timecop.freeze(lesson2.music_session.scheduled_start)
|
|
|
|
# causes find_bookings_needing_sessions to re-run
|
|
booking.sync_lessons
|
|
booking.reload
|
|
booking.lesson_sessions.length.should eql 4
|
|
|
|
# check that all the times make sense
|
|
|
|
lesson4 = booking.lesson_sessions[3]
|
|
lesson1.music_session.scheduled_start.to_i.should eql (lesson4.music_session.scheduled_start.to_i - (60 * 60 * 24 * 21))
|
|
end
|
|
|
|
it "ignores non-recurring" do
|
|
booking = LessonBooking.book_normal(user, teacher_user, valid_recurring_slots, "Hey I've heard of you before.", false, LessonBooking::PAYMENT_STYLE_SINGLE, 60)
|
|
booking.lesson_sessions.length.should eql 1
|
|
|
|
booking.accept(booking.lesson_sessions[0], booking.lesson_booking_slots[0], user)
|
|
booking.errors.any?.should be false
|
|
booking.reload
|
|
booking.lesson_sessions.length.should eql 1
|
|
booking.accepter.should eql user
|
|
end
|
|
end
|
|
|
|
describe "canceling" do
|
|
|
|
after do
|
|
Timecop.return
|
|
end
|
|
|
|
it "single session gets canceled before accepted" do
|
|
|
|
booking = LessonBooking.book_normal(user, teacher_user, valid_single_slots, "Hey I've heard of you before.", false, LessonBooking::PAYMENT_STYLE_SINGLE, 60)
|
|
lesson_session = booking.lesson_sessions[0]
|
|
lesson_session.status.should eql LessonSession::STATUS_REQUESTED
|
|
lesson_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)
|
|
|
|
# avoid 24 hour problem
|
|
|
|
UserMailer.deliveries.clear
|
|
Timecop.freeze(7.days.ago)
|
|
lesson_session.cancel({canceler: teacher_user, message: 'meh', slot: booking.default_slot.id, update_all: false})
|
|
lesson_session.errors.any?.should be_false
|
|
lesson_session.reload
|
|
lesson_session.status.should eql LessonSession::STATUS_CANCELED
|
|
lesson_session.reload
|
|
booking.reload
|
|
booking.status.should eql LessonSession::STATUS_CANCELED
|
|
UserMailer.deliveries.length.should eql 1
|
|
end
|
|
|
|
it "single session gets canceled after accepted" do
|
|
booking = LessonBooking.book_normal(user, teacher_user, valid_single_slots, "Hey I've heard of you before.", false, LessonBooking::PAYMENT_STYLE_SINGLE, 60)
|
|
lesson_session = booking.lesson_sessions[0]
|
|
lesson_session.status.should eql LessonSession::STATUS_REQUESTED
|
|
lesson_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)
|
|
|
|
lesson_session.accept({accepter: teacher_user, message: 'Yeah I got this', slot: booking.default_slot.id, update_all: false})
|
|
lesson_session.errors.any?.should be_false
|
|
lesson_session.status.should eql LessonSession::STATUS_APPROVED
|
|
lesson_session.reload
|
|
lesson_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)
|
|
|
|
UserMailer.deliveries.clear
|
|
Timecop.freeze(7.days.ago)
|
|
lesson_session.cancel({canceler: user, message: 'meh', slot: booking.default_slot.id, update_all: false})
|
|
lesson_session.errors.any?.should be_false
|
|
lesson_session.reload
|
|
lesson_session.status.should eql LessonSession::STATUS_CANCELED
|
|
booking.reload
|
|
booking.status.should eql LessonSession::STATUS_CANCELED
|
|
UserMailer.deliveries.length.should eql 2
|
|
end
|
|
|
|
it "recurring session gets canceled after accepted" do
|
|
booking = LessonBooking.book_normal(user, teacher_user, valid_recurring_slots, "Hey I've heard of you before.", true, LessonBooking::PAYMENT_STYLE_MONTHLY, 60)
|
|
booking.active.should eql false
|
|
lesson_session = booking.lesson_sessions[0]
|
|
lesson_session.status.should eql LessonSession::STATUS_REQUESTED
|
|
lesson_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)
|
|
|
|
lesson_session.accept({accepter: teacher_user, message: 'Yeah I got this', slot: booking.default_slot.id, update_all: false})
|
|
lesson_session.errors.any?.should be_false
|
|
lesson_session.status.should eql LessonSession::STATUS_APPROVED
|
|
lesson_session.reload
|
|
lesson_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)
|
|
booking.reload
|
|
booking.active.should eql true
|
|
|
|
UserMailer.deliveries.clear
|
|
Timecop.freeze(7.days.ago)
|
|
lesson_session.cancel({canceler: user, message: 'meh', slot: booking.default_slot.id, update_all: false})
|
|
lesson_session.errors.any?.should be_false
|
|
lesson_session.status.should eql LessonSession::STATUS_CANCELED
|
|
lesson_session.reload
|
|
lesson_session.canceler.should eql user
|
|
booking.reload
|
|
booking.active.should eql true
|
|
booking.status.should eql LessonSession::STATUS_APPROVED
|
|
booking.canceler.should be_nil
|
|
UserMailer.deliveries.length.should eql 2
|
|
end
|
|
|
|
it "recurring booking gets canceled after accepted" do
|
|
booking = LessonBooking.book_normal(user, teacher_user, valid_recurring_slots, "Hey I've heard of you before.", true, LessonBooking::PAYMENT_STYLE_MONTHLY, 60)
|
|
lesson_session = booking.lesson_sessions[0]
|
|
lesson_session.status.should eql LessonSession::STATUS_REQUESTED
|
|
lesson_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)
|
|
|
|
lesson_session.accept({accepter: teacher_user, message: 'Yeah I got this', slot: booking.default_slot.id, update_all: false})
|
|
lesson_session.errors.any?.should be_false
|
|
lesson_session.status.should eql LessonSession::STATUS_APPROVED
|
|
lesson_session.reload
|
|
lesson_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)
|
|
|
|
UserMailer.deliveries.clear
|
|
Timecop.freeze(7.days.ago)
|
|
lesson_session.cancel({canceler: user, message: 'meh', slot: booking.default_slot.id, update_all: true})
|
|
lesson_session.errors.any?.should be_false
|
|
lesson_session.reload
|
|
lesson_session.status.should eql LessonSession::STATUS_CANCELED
|
|
booking.reload
|
|
booking.status.should eql LessonSession::STATUS_CANCELED
|
|
booking.canceler.should eql user
|
|
UserMailer.deliveries.length.should eql 2
|
|
end
|
|
end
|
|
describe "rescheduling" do
|
|
|
|
after do
|
|
Timecop.return
|
|
end
|
|
it "non-recurring, accepted with new slot" do
|
|
booking = LessonBooking.book_normal(user, teacher_user, valid_single_slots, "Hey I've heard of you before.", false, LessonBooking::PAYMENT_STYLE_SINGLE, 60)
|
|
lesson_session = booking.lesson_sessions[0]
|
|
lesson_session.status.should eql LessonSession::STATUS_REQUESTED
|
|
lesson_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)
|
|
|
|
counter = FactoryGirl.build(:lesson_booking_slot_single, hour: 16)
|
|
lesson_session.counter({proposer: user, slot: counter, message: 'Does this work better?'})
|
|
lesson_session.errors.any?.should be false
|
|
lesson_session.status.should eql LessonSession::STATUS_COUNTERED
|
|
lesson_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)
|
|
booking.reload
|
|
booking.counter_slot.should eql counter
|
|
|
|
lesson_session.accept({accepter: teacher_user, message: 'Yeah I got this', slot: counter.id, update_all: false})
|
|
lesson_session.errors.any?.should be_false
|
|
lesson_session.status.should eql LessonSession::STATUS_APPROVED
|
|
lesson_session.reload
|
|
lesson_session.scheduled_start.should eql counter.scheduled_time(0)
|
|
booking.reload
|
|
booking.accepter.should eql teacher_user
|
|
booking.counter_slot.should be_nil
|
|
end
|
|
|
|
it "recurring" do
|
|
Timecop.freeze(Time.new(2016, 03, 4, 5, 0, 0))
|
|
booking = LessonBooking.book_normal(user, teacher_user, valid_recurring_slots, "Hey I've heard of you before.", true, LessonBooking::PAYMENT_STYLE_WEEKLY, 60)
|
|
lesson_session = booking.lesson_sessions[0]
|
|
lesson_session.status.should eql LessonSession::STATUS_REQUESTED
|
|
lesson_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)
|
|
|
|
counter = FactoryGirl.build(:lesson_booking_slot_recurring, day_of_week: 2)
|
|
lesson_session.counter({proposer: user, slot: counter, message: 'Does this work better?'})
|
|
lesson_session.errors.any?.should be false
|
|
lesson_session.status.should eql LessonSession::STATUS_COUNTERED
|
|
lesson_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)
|
|
|
|
# to help scoot out the 'created_at' of the lessons
|
|
Timecop.freeze(Time.now + 10)
|
|
|
|
lesson_session.accept({accepter: teacher_user, message: 'Yeah I got this', slot: counter.id, update_all: false})
|
|
lesson_session.errors.any?.should be_false
|
|
lesson_session.status.should eql LessonSession::STATUS_APPROVED
|
|
booking.reload
|
|
booking.status.should eql LessonSession::STATUS_APPROVED
|
|
|
|
lesson_session.reload
|
|
lesson_session.scheduled_start.should eql counter.scheduled_time(0)
|
|
|
|
lesson_session2 = booking.lesson_sessions.order(:created_at)[1]
|
|
lesson_session2.scheduled_start.should eql counter.scheduled_time(1)
|
|
|
|
# now it's approved, we have 2 sessions that are not yet completed with a time
|
|
|
|
# we should be able to reschedule just one of the lessons
|
|
counter2 = FactoryGirl.build(:lesson_booking_slot_recurring, day_of_week: 4, update_all: false)
|
|
lesson_session.counter({proposer: user, slot: counter2, message: 'ACtually, let\'s do this instead for just this one'})
|
|
lesson_session.errors.any?.should be false
|
|
lesson_session.status.should eql LessonSession::STATUS_COUNTERED
|
|
lesson_session.scheduled_start.should eql counter.scheduled_time(0)
|
|
|
|
lesson_session.accept({accepter: teacher_user, message: 'OK, lets fix just this one', slot: counter2.id})
|
|
lesson_session.errors.any?.should be_false
|
|
lesson_session.status.should eql LessonSession::STATUS_APPROVED
|
|
booking.reload
|
|
lesson_session.reload
|
|
lesson_session2.reload
|
|
lesson_session.scheduled_start.should eql counter2.scheduled_time(0)
|
|
lesson_session2.scheduled_start.should eql counter.scheduled_time(1) # STILL ORIGINAL COUNTER!
|
|
|
|
# we should be able to reschedule all of the lessons
|
|
|
|
|
|
counter3 = FactoryGirl.build(:lesson_booking_slot_recurring, day_of_week: 5, update_all: true)
|
|
lesson_session.counter({proposer: user, slot: counter3, message: 'ACtually, let\'s do this instead for just this one... again'})
|
|
lesson_session.errors.any?.should be false
|
|
lesson_session.status.should eql LessonSession::STATUS_COUNTERED
|
|
lesson_session.reload
|
|
lesson_session2.reload
|
|
lesson_session.scheduled_start.should eql counter2.scheduled_time(0)
|
|
lesson_session2.scheduled_start.should eql counter.scheduled_time(1)
|
|
booking.reload
|
|
booking.counter_slot.should eql counter3
|
|
|
|
|
|
lesson_session.accept({accepter: teacher_user, message: 'OK, lets fix all of them', slot: counter3.id})
|
|
lesson_session.errors.any?.should be_false
|
|
lesson_session.status.should eql LessonSession::STATUS_APPROVED
|
|
booking.reload
|
|
booking.counter_slot.should be_nil
|
|
lesson_session.reload
|
|
lesson_session2.reload
|
|
lesson_session.created_at.should be < lesson_session2.created_at
|
|
|
|
lesson_session.scheduled_start.should eql counter3.scheduled_time(0)
|
|
lesson_session2.scheduled_start.should eql counter3.scheduled_time(1 )
|
|
|
|
end
|
|
end
|
|
end
|