lesson fixes

This commit is contained in:
Seth Call 2016-05-26 18:10:05 -05:00
parent cc3576f70f
commit ea049068e0
13 changed files with 151 additions and 126 deletions

View File

@ -0,0 +1,14 @@
ActiveAdmin.register_page "Jam Class Knobs" do
menu :parent => 'JamClass'
page_action :force_hourly, :method => :post do
Resque.enqueue(HourlyJob)
redirect_to admin_jam_class_knobs_path, :notice => "Re-running the Hourly Job. Lessons will be analysed; any payments will be attempted that should be, etc"
end
action_item do
link_to "Force Hourly Background Job", admin_jam_class_knobs_force_hourly_path, :method => :post
end
end

View File

@ -28,7 +28,11 @@ ActiveAdmin.register JamRuby::LessonSession, :as => 'LessonSessions' do
end end
column "Start Time" do |lesson_session| column "Start Time" do |lesson_session|
span do span do
lesson_session.music_session.pretty_scheduled_start(true) if lesson_session.music_session.nil?
raise "Lessonsesison with no id #{lesson_session.id}"
else
lesson_session.music_session.pretty_scheduled_start(true)
end
end end
br br
span do span do
@ -92,6 +96,11 @@ ActiveAdmin.register JamRuby::LessonSession, :as => 'LessonSessions' do
lesson_session.sent_notices lesson_session.sent_notices
end end
end end
row "Success" do |lesson_session|
span do
lesson_session.success
end
end
row "Billed" do |lesson_session| row "Billed" do |lesson_session|
span do span do
lesson_session.billed lesson_session.billed

View File

@ -105,7 +105,6 @@ module JamRuby
lesson_session_id = lesson_session.id if lesson_session lesson_session_id = lesson_session.id if lesson_session
if music_notation if music_notation
puts "IS MUSIC NOTATION"
attachment_id = music_notation.id attachment_id = music_notation.id
attachment_type = music_notation.attachment_type attachment_type = music_notation.attachment_type
attachment_name = music_notation.file_name attachment_name = music_notation.file_name
@ -115,8 +114,6 @@ module JamRuby
attachment_name = claimed_recording.name attachment_name = claimed_recording.name
end end
puts "ATTACMENT #{}"
msg = @@message_factory.chat_message( msg = @@message_factory.chat_message(
music_session_id, music_session_id,

View File

@ -116,16 +116,15 @@ module JamRuby
end end
def self.analyse_sessions def self.analyse_sessions
MusicSession.joins(lesson_session: :lesson_booking).where('lesson_sessions.status = ?', LessonSession::STATUS_APPROVED).where("session_removed_at IS NOT NULL OR NOW() > scheduled_start + (INTERVAL '1 minutes' * duration)").where('analysed = false').each do |music_session| MusicSession.joins(lesson_session: :lesson_booking).where('lesson_sessions.status = ?', LessonSession::STATUS_APPROVED).where("NOW() > scheduled_start + (INTERVAL '1 minutes' * (3 + duration))").where('analysed = false').each do |music_session|
lession_session = music_session.lesson_session lession_session = music_session.lesson_session
@@log.debug("analysis lesson session #{lession_session.id}")
lession_session.analyse lession_session.analyse
end end
end end
def self.complete_sessions def self.complete_sessions
# this will find any paid session (recurring monthly paid, recurring single paid, single paid) # this will find any paid session (recurring monthly paid, recurring single paid, single paid)
MusicSession.joins(lesson_session: [:lesson_booking, :lesson_payment_charge]).where('lesson_sessions.status = ?', LessonSession::STATUS_COMPLETED).where("session_removed_at IS NOT NULL OR NOW() > scheduled_start + (INTERVAL '1 minutes' * duration)").where('analysed = true').where('lesson_sessions.post_processed = false').where('billing_should_retry = true').each do |music_session| MusicSession.joins(lesson_session: [:lesson_booking, :lesson_payment_charge]).where('lesson_sessions.status = ?', LessonSession::STATUS_COMPLETED).where("NOW() > scheduled_start + (INTERVAL '1 minutes' * (3 + duration))").where('analysed = true').where('lesson_sessions.post_processed = false').where('billing_should_retry = true').each do |music_session|
lession_session = music_session.lesson_session lession_session = music_session.lesson_session
lession_session.session_completed lession_session.session_completed
end end

View File

@ -43,6 +43,14 @@ context = window
timeString timeString
render: () -> render: () ->
if @props.lessonSession.isStudent
role = 'student'
otherRole = 'teacher'
billingStatement = 'charged for the lesson'
else
role = 'teacher'
otherRole = 'student'
billingStatement = 'not receive payment for the lesson'
if @props.lessonSession.completed if @props.lessonSession.completed
if @props.lessonSession.success if @props.lessonSession.success
content = `<div className="message"> content = `<div className="message">
@ -61,18 +69,19 @@ context = window
content = `<div className="message"> content = `<div className="message">
<p>You need to wait in this session for</p> <p>You need to wait in this session for</p>
<p className="time">{this.displayTime()}</p> <p className="time">{this.displayTime()}</p>
<p>to allow time for your teacher to join you. If you leave before this timer reaches zero, and your teacher joins this session, you will be marked absent and charged for the lesson.</p> <p>to allow time for your {otherRole} to join you. If you leave before this timer reaches zero, and your {otherRole} joins this session, you will be marked absent and {billingStatement}.</p>
</div>` </div>`
else if @props.lessonSession.teacherFault else if @props.lessonSession.teacherFault
if @props.lessonSession.teacherPresent? if @props.lessonSession.isStudent
content = `<div className="message"> content = `<div className="message">
<p>Because your teacher was late, you may now leave the session. However, if you choose to stay in the session with the teacher, after 5 minutes together the session will be considered a success, and you will be billed.</p> <p>You may now leave the session.</p>
<p>If the two of you do not spend at least 5 minutes together in the session, your teacher will be marked absent and penalized for missing the lesson, and you will not be charged for this lesson.</p> <p>Your teacher will be marked absent and penalized for missing the lesson. You will not be charged for this lesson.</p>
<p>We apologize for your inconvenience, and we will work to remedy this situation.</p>
</div>` </div>`
else else
content = `<div className="message"> content = `<div className="message">
<p>You may now leave the session.</p> <p>You may now leave the session.</p>
<p>Your teacher will be marked absent and penalized for missing the lesson. You will not be charged for this lesson.</p> <p>Your student will be marked absent and penalized for missing the lesson. You will still received payment for this lesson.</p>
<p>We apologize for your inconvenience, and we will work to remedy this situation.</p> <p>We apologize for your inconvenience, and we will work to remedy this situation.</p>
</div>` </div>`

View File

@ -105,13 +105,13 @@ LessonTimerActions = context.LessonTimerActions
title: 'Start Time Set', title: 'Start Time Set',
text: "Start time for session set to 5 mins from now" text: "Start time for session set to 5 mins from now"
}))) })))
else if data.lessonAction == 'start-35-ago' else if data.lessonAction == 'start-65-ago'
rest.lessonStartTime({ rest.lessonStartTime({
id: lessonId, id: lessonId,
minutes: -35 minutes: -65
}).done((response) => (@app.layout.notify({ }).done((response) => (@app.layout.notify({
title: 'Start Time Set', title: 'Start Time Set',
text: "Start time for session set to 35 mins ago" text: "Start time for session set to 65 mins ago"
}))) })))
else if data.lessonAction == 'enter-payment' else if data.lessonAction == 'enter-payment'
window.location.href = "/client#/jamclass/lesson-payment/lesson-booking_#{lessonId}" window.location.href = "/client#/jamclass/lesson-payment/lesson-booking_#{lessonId}"

View File

@ -177,7 +177,7 @@
<select className="hour">{this.hours}</select> : <select disabled={this.props.disabled} className="minute">{this.minutes}</select> <select className="hour">{this.hours}</select> : <select disabled={this.props.disabled} className="minute">{this.minutes}</select>
<select className="am_pm">{this.am_pm}</select> <select className="am_pm">{this.am_pm}</select>
<br/> <br/>
<span>* Time will be local to {context.JK.currentTimezone()}</span> <span>* Time will be local to {window.JK.currentTimezone()}</span>
{errorText} {errorText}
</span> </span>
@ -199,7 +199,7 @@
<select className="hour">{this.hours}</select> : <select disabled={this.props.disabled} className="minute">{this.minutes}</select> <select className="hour">{this.hours}</select> : <select disabled={this.props.disabled} className="minute">{this.minutes}</select>
<select disabled={this.props.disabled} className="am_pm">{this.am_pm}</select> <select disabled={this.props.disabled} className="am_pm">{this.am_pm}</select>
<br/> <br/>
<span>*Time will be local to {context.JK.currentTimezone()}</span> <span>*Time will be local to {window.JK.currentTimezone()}</span>
{errorText} {errorText}
</span> </span>
</div>` </div>`

View File

@ -38,7 +38,7 @@ ProfileActions = @ProfileActions
afterShow: (e) -> afterShow: (e) ->
UserActions.refresh() UserActions.refresh()
#@setState(TeacherSearchStore.getState()) #@setState(TeacherSearchStore.getState())
#if @state.results.length == 0 #if @state.results.length == 0
# don't issue a new search every time someone comes to the screen, to preserve location from previous browsing # don't issue a new search every time someone comes to the screen, to preserve location from previous browsing

View File

@ -93,7 +93,7 @@ BroadcastStore = Reflux.createStore(
@session = session @session = session
currentSession = session.session currentSession = session.session
if currentSession? && currentSession.lesson_session? && session.inSession() && currentSession.lesson_session.student_id == context.JK.currentUserId if currentSession? && currentSession.lesson_session? && session.inSession()
@currentSession = currentSession @currentSession = currentSession
@ -137,9 +137,13 @@ BroadcastStore = Reflux.createStore(
changed: () -> changed: () ->
if @currentLesson? if @currentLesson?
@currentLesson.isStudent == @currentLesson.student_id == context.JK.currentUserId
@currentLesson.isTeacher = !@currentLesson.isStudent
@currentLesson.teacherFault = @teacherFault @currentLesson.teacherFault = @teacherFault
@currentLesson.teacherPresent = @session.findParticipantByUserId(@currentLesson.teacher_id) @currentLesson.teacherPresent = @session.findParticipantByUserId(@currentLesson.teacher_id)
if @currentLesson.teacherPresent? @currentLesson.studentPresent = @session.findParticipantByUserId(@currentLesson.student_id)
if (@currentLesson.teacherPresent? && @currentLesson.isStudent) || (@currentLesson.studentPresent? && @currentLesson.isTeacher)
# don't show anything if the other person is there
this.trigger(null) this.trigger(null)
else else
this.trigger(@currentLesson) this.trigger(@currentLesson)

View File

@ -774,7 +774,6 @@ ConfigureTracksActions = @ConfigureTracksActions
context.JK.JamServer.registerMessageCallback(context.JK.MessageType.TRACKS_CHANGED, @trackChanges); context.JK.JamServer.registerMessageCallback(context.JK.MessageType.TRACKS_CHANGED, @trackChanges);
context.JK.JamServer.registerMessageCallback(context.JK.MessageType.HEARTBEAT_ACK, @trackChanges); context.JK.JamServer.registerMessageCallback(context.JK.MessageType.HEARTBEAT_ACK, @trackChanges);
console.log("SESSION STARTED EVENT")
$(document).trigger(EVENTS.SESSION_STARTED, {session: {id: @currentSessionId, lesson_session: response.lesson_session}}) if document $(document).trigger(EVENTS.SESSION_STARTED, {session: {id: @currentSessionId, lesson_session: response.lesson_session}}) if document
@handleAutoOpenJamTrack() @handleAutoOpenJamTrack()

View File

@ -64,8 +64,8 @@ script type='text/template' id='template-lesson-session-actions'
= '{% if (data.isAdmin) { %}' = '{% if (data.isAdmin) { %}'
li data-lesson-option="start-5-min" li data-lesson-option="start-5-min"
a href='#' Set Start In 5 Min a href='#' Set Start In 5 Min
li data-lesson-option="start-35-ago" li data-lesson-option="start-65-ago"
a href='#' Set Start 35 Min Ago a href='#' Set Start 65 Min Ago
= '{% } %}' = '{% } %}'
= '{% } else { %}' = '{% } else { %}'

View File

@ -1,10 +1,39 @@
require 'factory_girl' require 'factory_girl'
require 'timecop'
require 'rspec-rails'
require Rails.root.join('spec', 'support', 'lessons.rb')
namespace :lessons do namespace :lessons do
task book_completed: :environment do |task, args|
user = User.find_by_email(ENV['STUDENT'])
teacher = User.find_by_email(ENV['TEACHER'])
recurring = ENV['RECURRING'] == '1'
slots = []
Timecop.travel(Date.today - 5)
slots << FactoryGirl.build(:lesson_booking_slot_single, preferred_day: Date.today - 3, timezone: 'America/Chicago')
slots << FactoryGirl.build(:lesson_booking_slot_single, preferred_day: Date.today - 4, timezone: 'America/Chicago')
if recurring
payment_style = LessonBooking::PAYMENT_STYLE_MONTHLY
else
payment_style = LessonBooking::PAYMENT_STYLE_SINGLE
end
lesson = normal_lesson(user, teacher, {accept: true, finish: true, student_show:true, no_validate: true})
if lesson.errors.any?
puts lesson.errors.inspect
raise "lesson failed"
end
lesson = booking.lesson_sessions[0]
puts "http://localhost:3000/client#/jamclass/lesson-booking/#{lesson.id}"
end
task book_normal: :environment do |task, args| task book_normal: :environment do |task, args|
user = User.find_by_email(ENV['STUDENT_EMAIL']) user = User.find_by_email(ENV['STUDENT'])
teacher = User.find_by_email(ENV['TEACHER_EMAIL']) teacher = User.find_by_email(ENV['TEACHER'])
recurring = ENV['RECURRING'] == '1' recurring = ENV['RECURRING'] == '1'
slots = [] slots = []
@ -71,7 +100,7 @@ namespace :lessons do
lesson = booking.lesson_sessions[0] lesson = booking.lesson_sessions[0]
if user.most_recent_test_drive_purchase.nil? if user.most_recent_test_drive_purchase.nil?
LessonPackagePurchase.create(user, booking, LessonPackageType.test_drive_4) LessonPackagePurchase.create(user, lesson.booking, LessonPackageType.test_drive_4)
end end
#lesson.accept({message: 'Yeah I got this', slot: slots[0]}) #lesson.accept({message: 'Yeah I got this', slot: slots[0]})
@ -80,6 +109,6 @@ namespace :lessons do
#lesson.slot.should eql slots[0] #lesson.slot.should eql slots[0]
#lesson.status.should eql LessonSession::STATUS_APPROVED #lesson.status.should eql LessonSession::STATUS_APPROVED
puts "http://localhost:3000/client#/jamclass/lesson-booking/#{booking.id}" puts "http://localhost:3000/client#/jamclass/lesson-booking/#{lesson.booking.id}"
end end
end end

View File

@ -89,157 +89,122 @@ end
def testdrive_lesson(user, teacher, options = {finish: false, accept: true, cancel: false, miss: false, slots: nil, package_count: 4}) def book_lesson(user, teacher, options)
if options[:package_count].nil? if options[:package_count].nil?
options[:package_count] = 4 options[:package_count] = 4
end end
if options[:slots].nil? if options[:slots].nil?
slots = [] slots = []
slots << FactoryGirl.build(:lesson_booking_slot_single) if options[:monthly]
slots << FactoryGirl.build(:lesson_booking_slot_single) slots << FactoryGirl.build(:lesson_booking_slot_recurring)
slots << FactoryGirl.build(:lesson_booking_slot_recurring)
else
slots << FactoryGirl.build(:lesson_booking_slot_single)
slots << FactoryGirl.build(:lesson_booking_slot_single)
end
else else
slots = options[:slots] slots = options[:slots]
end end
if user.stored_credit_card == false if user.stored_credit_card == false
user.stored_credit_card = true token = create_stripe_token
user.save! result = user.payment_update({token: token, zip: '78759', normal: true})
#user.stored_credit_card = true
#user.save!
end end
booking = LessonBooking.book_test_drive(user, teacher, slots, "Hey I've heard of you before.") if options[:test_drive]
booking = LessonBooking.book_test_drive(user, teacher, slots, "Hey I've heard of you before.")
elsif options[:normal]
booking = LessonBooking.book_normal(user, teacher, slots, "Hey I've heard of you before.", false, LessonBooking::PAYMENT_STYLE_SINGLE, 60)
elsif options[:monthly]
booking = LessonBooking.book_normal(user, teacher, slots, "Hey I've heard of you before.", true, LessonBooking::PAYMENT_STYLE_MONTHLY, 60)
end
if booking.errors.any? if booking.errors.any?
puts "BOOKING #{booking.errors.inspect}" puts "BOOKING #{booking.errors.inspect}"
if booking.lesson_booking_slots[0].errors.any?
puts "SLOT0 #{booking.lesson_booking_slots[0].errors.inspect}"
end
end end
booking.errors.any?.should be_false
booking.errors.any?.should be_false unless options[:no_validate]
lesson = booking.lesson_sessions[0] lesson = booking.lesson_sessions[0]
start = lesson.scheduled_start start = lesson.scheduled_start
end_time = lesson.scheduled_start + (60 * lesson.duration) end_time = lesson.scheduled_start + (60 * lesson.duration)
booking.card_presumed_ok.should be_true booking.card_presumed_ok.should be_true unless options[:no_validate]
if user.most_recent_test_drive_purchase.nil? if options[:test_drive]
LessonPackagePurchase.create(user, booking, LessonPackageType.package_for_test_drive_count(options[:package_count])) if user.most_recent_test_drive_purchase.nil?
LessonPackagePurchase.create(user, booking, LessonPackageType.package_for_test_drive_count(options[:package_count]))
end
end end
if options[:accept] if options[:accept]
lesson.accept({message: 'Yeah I got this', slot: slots[0]}) lesson.accept({message: 'Yeah I got this', slot: slots[0]})
lesson.errors.any?.should be_false lesson.errors.any?.should be_false unless options[:no_validate]
lesson.reload lesson.reload
lesson.slot.should eql slots[0] lesson.slot.should eql slots[0] unless options[:no_validate]
lesson.status.should eql LessonSession::STATUS_APPROVED lesson.status.should eql LessonSession::STATUS_APPROVED unless options[:no_validate]
end end
if options[:cancel] if options[:cancel]
lesson.cancel({canceler: options[:canceler] || user, message: "sorry about that"}) lesson.cancel({canceler: options[:canceler] || user, message: "sorry about that"})
lesson.reload lesson.reload
lesson.status.should eql LessonSession::STATUS_CANCELED lesson.status.should eql LessonSession::STATUS_CANCELED unless options[:no_validate]
end end
if options[:miss] if options[:miss]
# teacher & student get into session Timecop.travel(end_time + 1)
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.analyse
lesson.session_completed lesson.session_completed
elsif options[:finish] elsif options[:finish]
# teacher & student get into session # teacher & student get into session
uh2 = FactoryGirl.create(:music_session_user_history, user: teacher, 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)
if options[:student_show]
uh2 = FactoryGirl.create(:music_session_user_history, user: user, history: lesson.music_session, created_at: start, session_removed_at: end_time)
end
# artificially end the session, which is covered by other background jobs # artificially end the session, which is covered by other background jobs
lesson.music_session.session_removed_at = end_time lesson.music_session.session_removed_at = end_time
lesson.music_session.save! lesson.music_session.save!
Timecop.travel(end_time + 1) Timecop.travel(end_time + 1)
lesson.analyse lesson.analyse
lesson.session_completed lesson.session_completed
if options[:monthly]
LessonBooking.hourly_check
end
end end
lesson lesson
end end
def testdrive_lesson(user, teacher, options = {finish: false, accept: true, cancel: false, miss: false, slots: nil})
options[:test_drive] = true
def normal_lesson(user, teacher, slots = nil) book_lesson(user, teacher, options)
if slots.nil?
slots = []
slots << FactoryGirl.build(:lesson_booking_slot_single)
slots << FactoryGirl.build(:lesson_booking_slot_single)
end
if user.stored_credit_card == false
user.stored_credit_card = true
user.save!
end
booking = LessonBooking.book_normal(user, teacher, slots, "Hey I've heard of you before.", false, LessonBooking::PAYMENT_STYLE_SINGLE, 60)
# puts "NORMAL BOOKING #{booking.errors.inspect}"
booking.errors.any?.should be_false
lesson = booking.lesson_sessions[0]
booking.card_presumed_ok.should be_true
#if user.most_recent_test_drive_purchase.nil?
# LessonPackagePurchase.create(user, booking, LessonPackageType.test_drive_4)
#end
lesson.accept({message: 'Yeah I got this', slot: slots[0]})
lesson.errors.any?.should be_false
lesson.reload
lesson.slot.should eql slots[0]
lesson.status.should eql LessonSession::STATUS_APPROVED
lesson.music_session.should_not be_nil
lesson
end end
def monthly_lesson(user, teacher, slots = nil) def normal_lesson(user, teacher, options = {finish: false, accept: true, cancel: false, miss: false, slots: nil})
options[:normal] = true
if slots.nil? book_lesson(user, teacher, options)
slots = []
slots << FactoryGirl.build(:lesson_booking_slot_recurring)
slots << FactoryGirl.build(:lesson_booking_slot_recurring)
end
if user.stored_credit_card == false
user.stored_credit_card = true
user.save!
end
booking = LessonBooking.book_normal(user, teacher, slots, "Hey I've heard of you before.", true, LessonBooking::PAYMENT_STYLE_MONTHLY, 60)
# puts "NORMAL BOOKING #{booking.errors.inspect}"
booking.errors.any?.should be_false
lesson = booking.lesson_sessions[0]
booking.card_presumed_ok.should be_true
#if user.most_recent_test_drive_purchase.nil?
# LessonPackagePurchase.create(user, booking, LessonPackageType.test_drive_4)
#end
lesson.accept({message: 'Yeah I got this', slot: slots[0]})
lesson.errors.any?.should be_false
lesson.reload
lesson.slot.should eql slots[0]
lesson.status.should eql LessonSession::STATUS_APPROVED
lesson.music_session.should_not be_nil
lesson
end end
def monthly_lesson(user, teacher, options = {finish: false, accept: true, cancel: false, miss: false, slots: nil})
options[:monthly] = true
book_lesson(user, teacher, options)
end