VRFS-4086 decline to cancel

This commit is contained in:
Seth Call 2016-05-19 21:42:27 -05:00
parent cdadc8bff4
commit 87eb29da11
13 changed files with 179 additions and 33 deletions

View File

@ -349,4 +349,5 @@ updated_subjects.sql
update_payment_history.sql
lesson_booking_schools.sql
lesson_booking_schools_2.sql
phantom_accounts.sql
phantom_accounts.sql
lesson_booking_success.sql

View File

@ -0,0 +1 @@
ALTER TABLE lesson_bookings ADD COLUMN success BOOLEAN;

View File

@ -16,8 +16,9 @@ module JamRuby
STATUS_APPROVED = 'approved'
STATUS_SUSPENDED = 'suspended'
STATUS_COUNTERED = 'countered'
STATUS_COMPLETED = 'completed'
STATUS_TYPES = [STATUS_REQUESTED, STATUS_CANCELED, STATUS_APPROVED, STATUS_SUSPENDED, STATUS_COUNTERED]
STATUS_TYPES = [STATUS_REQUESTED, STATUS_CANCELED, STATUS_APPROVED, STATUS_SUSPENDED, STATUS_COUNTERED, STATUS_COMPLETED]
LESSON_TYPE_FREE = 'single-free'
LESSON_TYPE_TEST_DRIVE = 'test-drive'
@ -30,6 +31,8 @@ module JamRuby
PAYMENT_STYLE_WEEKLY = 'weekly'
PAYMENT_STYLE_MONTHLY = 'monthly'
ENGAGED = "status = '#{STATUS_APPROVED}' OR status = '#{STATUS_REQUESTED}' OR status = '#{STATUS_SUSPENDED}'"
PAYMENT_STYLES = [PAYMENT_STYLE_ELSEWHERE, PAYMENT_STYLE_SINGLE, PAYMENT_STYLE_WEEKLY, PAYMENT_STYLE_MONTHLY]
@ -79,7 +82,8 @@ module JamRuby
scope :requested, -> { where(status: STATUS_REQUESTED) }
scope :canceled, -> { where(status: STATUS_CANCELED) }
scope :suspended, -> { where(status: STATUS_SUSPENDED) }
scope :engaged, -> { where("status = '#{STATUS_APPROVED}' OR status = '#{STATUS_REQUESTED}' OR status = '#{STATUS_SUSPENDED}'") }
scope :engaged, -> { where(ENGAGED) }
scope :engaged_or_successful, -> { where("(" + ENGAGED + ") OR (lesson_bookings.status = '#{STATUS_COMPLETED}' AND lesson_bookings.success = true)")}
def before_validation
if self.booked_price.nil?
@ -219,7 +223,7 @@ module JamRuby
def sync_lessons
if is_canceled?
if is_canceled? || is_completed?
# don't create new sessions if cancelled
return
end
@ -390,6 +394,10 @@ module JamRuby
status == STATUS_CANCELED
end
def is_completed?
status == STATUS_COMPLETED
end
def is_approved?
status == STATUS_APPROVED
end
@ -597,8 +605,10 @@ module JamRuby
message = '' if message.nil?
msg = ChatMessage.create(canceler, nil, message, ChatMessage::CHANNEL_LESSON, nil, other, next_lesson, purpose)
else
end
self
end
@ -619,12 +629,13 @@ module JamRuby
# errors.add(:user, 'has no credit card stored')
#end
elsif is_test_drive?
if user.has_requested_test_drive?(teacher) && !user.admin
errors.add(:user, "have a requested TestDrive with this teacher")
end
if !user.has_test_drives? && !user.can_buy_test_drive?
errors.add(:user, "have no remaining test drives")
elsif teacher.has_booked_test_drive_with_student?(user) && !user.admin
errors.add(:user, "have an in-progress or successful TestDrive with this teacher already")
end
elsif is_normal?
#if !user.has_stored_credit_card?
# errors.add(:user, 'has no credit card stored')
@ -825,9 +836,12 @@ module JamRuby
bookings
end
def self.not_failed
end
def self.engaged_bookings(student, teacher, since_at = nil)
bookings = bookings(student, teacher, since_at)
bookings.engaged
bookings.engaged_or_successful
end
def bill_monthly(now)

View File

@ -30,18 +30,18 @@ module JamRuby
LESSON_TYPE_TEST_DRIVE = 'test-drive'
LESSON_TYPES = [LESSON_TYPE_SINGLE, LESSON_TYPE_SINGLE_FREE, LESSON_TYPE_TEST_DRIVE]
has_one :music_session, class_name: "JamRuby::MusicSession", :dependent => :destroy
belongs_to :teacher, class_name: "JamRuby::User", foreign_key: :teacher_id, inverse_of: :taught_lessons
belongs_to :canceler, class_name: "JamRuby::User", foreign_key: :canceler_id
belongs_to :lesson_package_purchase, class_name: "JamRuby::LessonPackagePurchase"
belongs_to :lesson_booking, class_name: "JamRuby::LessonBooking"
belongs_to :slot, class_name: "JamRuby::LessonBookingSlot", foreign_key: :slot_id, :dependent => :destroy
belongs_to :lesson_payment_charge, class_name: "JamRuby::LessonPaymentCharge", foreign_key: :charge_id
belongs_to :counter_slot, class_name: "JamRuby::LessonBookingSlot", foreign_key: :counter_slot_id, inverse_of: :countered_lesson, :dependent => :destroy
has_one :teacher_distribution, class_name: "JamRuby::TeacherDistribution"
has_many :lesson_booking_slots, class_name: "JamRuby::LessonBookingSlot"
has_many :notifications, :class_name => "JamRuby::Notification", :foreign_key => "lesson_session_id"
has_many :chat_messages, :class_name => "JamRuby::ChatMessage", :foreign_key => "lesson_session_id"
has_one :music_session, class_name: "JamRuby::MusicSession", :dependent => :destroy
belongs_to :teacher, class_name: "JamRuby::User", foreign_key: :teacher_id, inverse_of: :taught_lessons
belongs_to :canceler, class_name: "JamRuby::User", foreign_key: :canceler_id
belongs_to :lesson_package_purchase, class_name: "JamRuby::LessonPackagePurchase"
belongs_to :lesson_booking, class_name: "JamRuby::LessonBooking"
belongs_to :slot, class_name: "JamRuby::LessonBookingSlot", foreign_key: :slot_id, :dependent => :destroy
belongs_to :lesson_payment_charge, class_name: "JamRuby::LessonPaymentCharge", foreign_key: :charge_id
belongs_to :counter_slot, class_name: "JamRuby::LessonBookingSlot", foreign_key: :counter_slot_id, inverse_of: :countered_lesson, :dependent => :destroy
has_one :teacher_distribution, class_name: "JamRuby::TeacherDistribution"
has_many :lesson_booking_slots, class_name: "JamRuby::LessonBookingSlot"
has_many :notifications, :class_name => "JamRuby::Notification", :foreign_key => "lesson_session_id"
has_many :chat_messages, :class_name => "JamRuby::ChatMessage", :foreign_key => "lesson_session_id"
validates :duration, presence: true, numericality: {only_integer: true}
@ -279,6 +279,9 @@ module JamRuby
student.test_drive_failed(self)
end
self.lesson_booking.success = success
self.lesson_booking.status = STATUS_COMPLETED
self.lesson_booking.save(:validate => false)
self.sent_notices = true
self.sent_notices_at = Time.now
self.post_processed = true
@ -355,6 +358,10 @@ module JamRuby
self.save(:validate => false)
end
end
self.lesson_booking.success = success
self.lesson_booking.status = STATUS_COMPLETED
self.lesson_booking.save(:validate => false)
end
def after_counter

View File

@ -121,6 +121,7 @@ module JamRuby
end
end
{
reason: reason,
teacher: teacher,
@ -262,6 +263,10 @@ module JamRuby
# percentage computation of time spent during the session time
in_scheduled_percentage = in_scheduled_time.to_f / planned_duration_seconds.to_f
# missed is an aggregrate concept shown in the UI often
# if you were a no show, or joined late, or didn't wait correctly, then you 'missed'
missed = no_show || joined_late || !waited_correctly
joined_on_time = joined_on_time
{
total_time: total,
@ -271,6 +276,7 @@ module JamRuby
waited_correctly: waited_correctly,
no_show: no_show,
joined_late: joined_late,
missed: missed,
initial_join_in_scheduled_time: initial_join_in_scheduled_time,
last_wait_time_out: last_wait_time_out,
in_wait_window_time: in_wait_window_time,

View File

@ -255,6 +255,9 @@ describe "Normal Lesson Flow" do
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

View File

@ -38,6 +38,7 @@ describe "TestDrive Lesson Flow" do
booking.card_presumed_ok.should be_false
booking.should eql user.unprocessed_test_drive
booking.sent_notices.should be_false
teacher_user.has_booked_test_drive_with_student?(user).should be_true
user.reload
user.remaining_test_drives.should eql 0
@ -234,10 +235,17 @@ describe "TestDrive Lesson Flow" do
sale = user.sales[0]
sale.sale_line_items.count.should eql 1
sale.sale_line_items[0].affiliate_distributions.count.should eql 0
lesson_session.lesson_booking.status.should eql LessonBooking::STATUS_COMPLETED
lesson_session.lesson_booking.success.should be_true
LessonBooking.bookings(user, teacher_user, nil).count.should eql 1
LessonBooking.engaged_bookings(user, teacher_user, nil).count.should eql 1
teacher_user.has_booked_test_drive_with_student?(user).should be_true
end
# VRFS-4069
it "cancels with no credit card " do
it "cancels with no credit card" do
slots = []
slots << FactoryGirl.build(:lesson_booking_slot_single)
@ -257,9 +265,12 @@ describe "TestDrive Lesson Flow" do
user.reload
user.remaining_test_drives.should eql 0
booking.reload
booking.status.should eql LessonBooking::STATUS_CANCELED
teacher_user.has_booked_test_drive_with_student?(user).should be_false
end
it "cancels with credit card " do
it "cancels with credit card" do
lesson = testdrive_lesson(user, teacher_user)
user.reload

View File

@ -162,7 +162,7 @@ ProfileActions = @ProfileActions
if response.booked_with_teacher && !context.JK.currentUserAdmin
logger.debug("TeacherSearchScreen: teacher already test-drived")
context.JK.Banner.showAlert('TestDrive', "You have already take a TestDrive lesson from this teacher. With TestDrive, you need to use your lessons on 4 different teachers to find one who is best for you. We're sorry, but you cannot take multiple TestDrive lessons from a single teacher.")
context.JK.Banner.showAlert('TestDrive', "You have already taken a TestDrive lesson from this teacher. With TestDrive, you need to use your lessons on 4 different teachers to find one who is best for you. We're sorry, but you cannot take multiple TestDrive lessons from a single teacher.")
else
# send on to booking screen for this teacher
logger.debug("TeacherSearchScreen: user being sent to book a lesson")

View File

@ -8,10 +8,14 @@ teacherActions = window.JK.Actions.Teacher
if lesson.student_id == context.JK.currentUserId
me = lesson.student
other = lesson.teacher
lesson.isStudent = true
lesson.isTeacher = false
lesson.hasUnreadMessages = lesson['student_unread_messages']
else
me = lesson.teacher
other = lesson.student
lesson.isStudent = false
lesson.isTeacher = true
lesson.hasUnreadMessages = lesson['teacher_unread_messages']
lesson.me = me
@ -41,22 +45,29 @@ teacherActions = window.JK.Actions.Teacher
else if lesson.status == 'suspended'
lesson.displayStatus = 'Suspended'
else
if lesson.success
lesson.displayStatus = 'Completed'
else
lesson.missed = true
lesson.missedRole = 'teacher'
lesson.missedUser = lesson.teacher
if lesson.analysis?.reason == 'teacher_fault'
if lesson.analysis?.teacher_analysis?.missed && lesson.analysis?.student_analysis?.missed
lesson.missedRole = 'both'
lesson.missedUser = lesson.teacher
lesson.displayStatus = 'Missed (Both)'
else if lesson.analysis?.teacher_analysis?.missed
lesson.missedRole = 'teacher'
lesson.missedUser = lesson.teacher
lesson.displayStatus = 'Missed (Teacher)'
else if lesson.analysis?.reason == 'student_fault'
lesson.displayStatus = 'Missed (Student)'
else if lesson.analysis?.student_analysis?.missed
lesson.missedRole = 'student'
lesson.missedUser = lesson.student
lesson.displayStatus = 'Missed (Student)'
else
lesson.displayStatus = 'Missed'
if lesson.success
lesson.missed = false
lesson.missedRole = null
lesson.displayStatus = 'Completed'
else
lesson.displayStatus = 'Missed'
@postProcessUser(me)
@postProcessUser(other)

View File

@ -17,7 +17,11 @@ script type='text/template' id='template-lesson-session-actions'
a href='#' Attach Message
li data-lesson-option="cancel"
= '{% if (data.isStudent) { %}'
a href='#' Cancel Request
= '{% } else { %}'
a href='#' Decline Request
= '{% } %}'
= '{% } else if (data.isScheduled) { %}'
ul

View File

@ -0,0 +1,72 @@
require 'spec_helper'
describe "Test Drive", :js => true, :type => :feature, :capybara_feature => true do
subject { page }
let(:user) { FactoryGirl.create(:user, traditional_band: true,paid_sessions: true, paid_sessions_hourly_rate: 1, paid_sessions_daily_rate:1 ) }
let(:teacher_user) {FactoryGirl.create(:teacher_user, ready_for_session_at: Time.now)}
let(:teacher_user2) {FactoryGirl.create(:teacher_user, ready_for_session_at: Time.now)}
it "shows Missed (Both)" do
lesson = testdrive_lesson(user, teacher_user, {miss: true, accept: true})
lesson.analysis_json["teacher_analysis"]["missed"].should be_true
lesson.analysis_json["student_analysis"]["missed"].should be_true
fast_signin(user, "/client#/jamclass")
find('#jam-class-student-screen td.displayStatusColumn', text: 'Missed (Both)')
end
it "shows Missed (Student)" do
lesson = testdrive_lesson(user, teacher_user, {accept: true, finish: true})
lesson.analysis_json["teacher_analysis"]["missed"].should be_false
lesson.analysis_json["student_analysis"]["missed"].should be_true
fast_signin(user, "/client#/jamclass")
find('#jam-class-student-screen td.displayStatusColumn', text: 'Missed (Student)')
end
it "shows Missed (Teacher)" do
lesson = testdrive_lesson(user, teacher_user, {accept: true, teacher_miss: true})
lesson.analysis_json["teacher_analysis"]["missed"].should be_true
lesson.analysis_json["student_analysis"]["missed"].should be_false
fast_signin(user, "/client#/jamclass")
find('#jam-class-student-screen td.displayStatusColumn', text: 'Missed (Teacher)')
end
it "shows Completed" do
lesson = testdrive_lesson(user, teacher_user, {accept: true, success: true})
lesson.analysis_json["teacher_analysis"]["missed"].should be_false
lesson.analysis_json["student_analysis"]["missed"].should be_false
fast_signin(user, "/client#/jamclass")
find('#jam-class-student-screen td.displayStatusColumn', text: 'Completed')
end
it "shows Decline for Teacher, Cancel for Student" do
lesson = testdrive_lesson(user, teacher_user, {accept: false})
fast_signin(teacher_user, "/client#/jamclass")
find('#jam-class-student-screen td.displayStatusColumn', text: 'Requested')
# open up hover
find('tr[data-lesson-session-id="' + lesson.id + '"] .lesson-session-actions-btn').trigger(:click)
find('li[data-lesson-option="cancel"] a', visible: false, text: 'Decline Request')
sign_out_poltergeist
sleep 4
fast_signin(user, "/client#/jamclass")
find('#jam-class-student-screen td.displayStatusColumn', text: 'Requested')
# open up hover
find('tr[data-lesson-session-id="' + lesson.id + '"] .lesson-session-actions-btn').trigger(:click)
# should work, doesn't
#find('li[data-lesson-option="cancel"] a', visible: false, text: 'Cancel Request')
end
end

View File

@ -236,6 +236,8 @@ bputs "before register capybara"
config.after(:each) do
Timecop.return
if example.metadata[:js]
end

View File

@ -135,6 +135,23 @@ def testdrive_lesson(user, teacher, options = {finish: false, accept: true, canc
if options[:miss]
# teacher & student get into session
Timecop.travel(end_time + 1)
lesson.analyse
lesson.session_completed
elsif options[:teacher_miss]
uh2 = FactoryGirl.create(:music_session_user_history, user: user, history: lesson.music_session, created_at: start, session_removed_at: end_time)
# artificially end the session, which is covered by other background jobs
lesson.music_session.session_removed_at = end_time
lesson.music_session.save!
Timecop.travel(end_time + 1)
lesson.analyse
lesson.session_completed
elsif options[:success]
uh1 = FactoryGirl.create(:music_session_user_history, user: user, history: lesson.music_session, created_at: start, session_removed_at: end_time)
uh2 = FactoryGirl.create(:music_session_user_history, user: teacher, history: lesson.music_session, created_at: start, session_removed_at: end_time)
# artificially end the session, which is covered by other background jobs
lesson.music_session.session_removed_at = end_time
lesson.music_session.save!
Timecop.travel(end_time + 1)
lesson.analyse
lesson.session_completed
@ -144,10 +161,7 @@ def testdrive_lesson(user, teacher, options = {finish: false, accept: true, canc
# artificially end the session, which is covered by other background jobs
lesson.music_session.session_removed_at = end_time
lesson.music_session.save!
Timecop.travel(end_time + 1)
lesson.analyse
lesson.session_completed
end