2021-02-01 14:56:47 +00:00
= begin
2016-04-06 02:23:15 +00:00
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 ) }
2017-07-17 00:38:40 +00:00
let ( :lesson_booking_slot_recurring1 ) { FactoryGirl . build ( :lesson_booking_slot_recurring , day_of_week : 2 . days . from_now . wday ) }
let ( :lesson_booking_slot_recurring2 ) { FactoryGirl . build ( :lesson_booking_slot_recurring , day_of_week : 3 . days . from_now . wday ) }
2016-04-06 02:23:15 +00:00
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
2016-04-22 19:59:48 +00:00
user . card_approved ( create_stripe_token , '78759' , booking . id )
2016-04-06 02:23:15 +00:00
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
2016-05-12 21:29:27 +00:00
user . card_approved ( create_stripe_token , '78759' , nil )
2016-04-06 02:23:15 +00:00
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
2016-04-22 19:59:48 +00:00
user . card_approved ( create_stripe_token , '78759' , booking . id )
2016-04-06 02:23:15 +00:00
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
2016-05-16 16:39:20 +00:00
after do
2016-04-06 02:23:15 +00:00
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 )
2016-07-17 15:16:27 +00:00
billables . all . to_a . should eql [ booking ]
2016-04-06 02:23:15 +00:00
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 )
2017-01-17 18:24:49 +00:00
times = booking . predicted_times_for_month ( next_year , 1 ) [ :times ]
2016-04-06 02:23:15 +00:00
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 )
2017-01-17 18:24:49 +00:00
times = booking . predicted_times_for_month ( next_year , 1 ) [ :times ]
2016-04-06 02:23:15 +00:00
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 )
2016-05-23 17:26:32 +00:00
times [ :times ] . length . should eql 2
times [ :times ] [ 0 ] . to_date . should eql ( Date . new ( next_year , 1 , 1 ) )
times [ :times ] [ 1 ] . to_date . should eql ( Date . new ( next_year , 1 , 29 ) )
2016-04-06 02:23:15 +00:00
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
2016-04-21 14:23:29 +00:00
chat_message = ChatMessage . where ( lesson_session_id : booking . next_lesson . id ) . first
2016-04-06 02:23:15 +00:00
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
2016-04-21 14:23:29 +00:00
chat_message = ChatMessage . where ( lesson_session_id : booking . next_lesson . id ) . first
2016-04-06 02:23:15 +00:00
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
2016-04-21 14:23:29 +00:00
chat_message = ChatMessage . where ( lesson_session_id : booking . next_lesson . id ) . first
2016-04-06 02:23:15 +00:00
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
2016-05-23 17:26:32 +00:00
booking . errors [ :user ] . should eq [ " have an in-progress or successful TestDrive with this teacher already " ]
2016-04-06 02:23:15 +00:00
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
2016-04-21 14:23:29 +00:00
chat_message = ChatMessage . where ( lesson_session_id : booking . next_lesson . id ) . first
2016-04-06 02:23:15 +00:00
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
2016-04-21 14:23:29 +00:00
chat_message = ChatMessage . where ( lesson_session_id : booking . next_lesson . id ) . first
2016-04-06 02:23:15 +00:00
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
2016-04-21 14:23:29 +00:00
it " allows long message to flow through chat " do
2016-04-06 02:23:15 +00:00
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
2016-04-21 14:23:29 +00:00
chat_message = ChatMessage . where ( lesson_session_id : booking . next_lesson . id ) . first
2016-04-06 02:23:15 +00:00
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 )
2017-07-17 00:38:40 +00:00
booking . errors . any? . should be true
booking . errors [ :accepter ] . should eql [ " No one has been indicated as accepting the lesson " ]
2016-04-06 02:23:15 +00:00
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
2016-04-21 14:23:29 +00:00
lesson_session . reload
2016-04-06 02:23:15 +00:00
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
2016-04-21 14:23:29 +00:00
lesson_session . status . should eql LessonSession :: STATUS_CANCELED
2016-04-06 02:23:15 +00:00
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 )
2017-07-17 00:38:40 +00:00
lesson_session . accept ( { accepter : teacher_user , message : 'Yeah I got this' , slot : booking . default_slot . id , update_all : true } )
2016-04-06 02:23:15 +00:00
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
2017-07-17 00:38:40 +00:00
booking . status . should eql LessonSession :: STATUS_APPROVED
2016-04-06 02:23:15 +00:00
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 )
2016-05-30 21:43:55 +00:00
mailer = mock
2016-07-17 15:16:27 +00:00
mailer . should_receive ( :deliver_now ) . exactly ( 2 ) . times
2016-05-30 21:43:55 +00:00
UserMailer . should_receive ( :student_lesson_booking_canceled ) . and_return ( mailer )
UserMailer . should_receive ( :teacher_lesson_booking_canceled ) . and_return ( mailer )
UserMailer . should_receive ( :student_lesson_canceled ) . exactly ( 0 ) . times
UserMailer . should_receive ( :teacher_lesson_canceled ) . exactly ( 0 ) . times
2016-04-06 02:23:15 +00:00
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
2016-04-21 14:23:29 +00:00
lesson_session . status . should eql LessonSession :: STATUS_CANCELED
2016-04-06 02:23:15 +00:00
booking . reload
booking . status . should eql LessonSession :: STATUS_CANCELED
booking . canceler . should eql user
end
end
describe " rescheduling " do
2016-05-30 03:30:33 +00:00
it " initial slot is in the past " 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 ]
initial_scheduled_time = lesson_session . scheduled_start
counter = FactoryGirl . build ( :lesson_booking_slot_single , preferred_day : Date . today + 20 )
lesson_session . counter ( { proposer : user , slot : counter , message : 'ACtually, let\'s do this instead for just this one' } )
Timecop . travel ( initial_scheduled_time + 1 )
2016-07-17 15:16:27 +00:00
lesson_session . accept ( { accepter : teacher_user , message : 'Yeah I got this' , slot : counter . id , update_all : false } )
2016-05-30 03:30:33 +00:00
booking . reload
booking . status . should eql LessonBooking :: STATUS_APPROVED
booking . lesson_sessions . count . should eql 1
lesson_session . errors . any? . should be_false
lesson_session . reload
lesson_session . status . should eql LessonSession :: STATUS_APPROVED
lesson_session . scheduled_start . should eql counter . scheduled_time ( 0 )
2016-04-06 02:23:15 +00:00
end
2016-05-30 03:30:33 +00:00
2016-04-06 02:23:15 +00:00
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 )
2017-07-17 00:38:40 +00:00
lesson_session . counter_slot . should eql counter
2016-04-06 02:23:15 +00:00
booking . reload
2017-07-17 00:38:40 +00:00
booking . counter_slot . should be_nil
2016-04-06 02:23:15 +00:00
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 ) )
2017-07-17 00:38:40 +00:00
booking = LessonBooking . book_normal ( user , teacher_user , valid_recurring_slots , " Hey I've heard of you before. " , true , LessonBooking :: PAYMENT_STYLE_MONTHLY , 60 )
2016-04-06 02:23:15 +00:00
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 )
2016-07-17 15:16:27 +00:00
counter = FactoryGirl . build ( :lesson_booking_slot_recurring , day_of_week : 2 , update_all : true )
2016-04-06 02:23:15 +00:00
lesson_session . counter ( { proposer : user , slot : counter , message : 'Does this work better?' } )
lesson_session . errors . any? . should be false
2017-07-17 00:38:40 +00:00
lesson_session . status . should eql LessonSession :: STATUS_REQUESTED
2016-04-06 02:23:15 +00:00
lesson_session . scheduled_start . should eql booking . default_slot . scheduled_time ( 0 )
2017-07-17 00:38:40 +00:00
booking . reload
booking . counter_slot . should eql counter
booking . counterer . should eql user
booking . has_recurring_counter? . should be true
booking . is_countered? . should be true
2016-04-06 02:23:15 +00:00
# to help scoot out the 'created_at' of the lessons
Timecop . freeze ( Time . now + 10 )
2017-07-17 00:38:40 +00:00
lesson_session . accept ( { accepter : teacher_user , message : 'Yeah I got this' , slot : counter . id } )
2016-04-06 02:23:15 +00:00
lesson_session . errors . any? . should be_false
lesson_session . status . should eql LessonSession :: STATUS_APPROVED
booking . reload
booking . status . should eql LessonSession :: STATUS_APPROVED
2017-07-17 00:38:40 +00:00
booking . has_recurring_counter? . should be false
booking . is_countered? . should be false
2016-04-06 02:23:15 +00:00
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
2017-07-17 00:38:40 +00:00
counter2 = FactoryGirl . build ( :lesson_booking_slot_single , day_of_week : 4 )
2016-04-06 02:23:15 +00:00
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
2017-07-17 00:38:40 +00:00
lesson_session . has_recurring_counter? . should be false
booking . reload
booking . status . should eql LessonSession :: STATUS_APPROVED
2016-04-06 02:23:15 +00:00
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
2017-07-17 00:38:40 +00:00
lesson_session . status . should eql LessonSession :: STATUS_APPROVED
2016-04-06 02:23:15 +00:00
lesson_session . reload
2017-07-17 00:38:40 +00:00
lesson_session . has_recurring_counter? . should be true
2016-04-06 02:23:15 +00:00
lesson_session2 . reload
2017-07-17 00:38:40 +00:00
lesson_session2 . has_recurring_counter? . should be true
2016-04-06 02:23:15 +00:00
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
2017-07-17 00:38:40 +00:00
lesson_session . reload
lesson_session . has_recurring_counter? . should be false
lesson_session2 . reload
lesson_session2 . has_recurring_counter? . should be false
2016-04-06 02:23:15 +00:00
lesson_session . created_at . should be < lesson_session2 . created_at
lesson_session . scheduled_start . should eql counter3 . scheduled_time ( 0 )
2017-07-17 00:38:40 +00:00
lesson_session2 . scheduled_start . should eql counter3 . scheduled_time ( 1 )
2016-04-06 02:23:15 +00:00
end
end
end
2021-02-01 14:56:47 +00:00
= end