diff --git a/admin/app/admin/jam_class_knobs.rb b/admin/app/admin/jam_class_knobs.rb new file mode 100644 index 000000000..f27e3f0e0 --- /dev/null +++ b/admin/app/admin/jam_class_knobs.rb @@ -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 \ No newline at end of file diff --git a/admin/app/admin/lesson_session.rb b/admin/app/admin/lesson_session.rb index 914174408..58ebe2d68 100644 --- a/admin/app/admin/lesson_session.rb +++ b/admin/app/admin/lesson_session.rb @@ -28,7 +28,11 @@ ActiveAdmin.register JamRuby::LessonSession, :as => 'LessonSessions' do end column "Start Time" do |lesson_session| 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 br span do @@ -92,6 +96,11 @@ ActiveAdmin.register JamRuby::LessonSession, :as => 'LessonSessions' do lesson_session.sent_notices end end + row "Success" do |lesson_session| + span do + lesson_session.success + end + end row "Billed" do |lesson_session| span do lesson_session.billed diff --git a/ruby/lib/jam_ruby/models/chat_message.rb b/ruby/lib/jam_ruby/models/chat_message.rb index 60ef217c7..bcd75fb5a 100644 --- a/ruby/lib/jam_ruby/models/chat_message.rb +++ b/ruby/lib/jam_ruby/models/chat_message.rb @@ -105,7 +105,6 @@ module JamRuby lesson_session_id = lesson_session.id if lesson_session if music_notation - puts "IS MUSIC NOTATION" attachment_id = music_notation.id attachment_type = music_notation.attachment_type attachment_name = music_notation.file_name @@ -115,8 +114,6 @@ module JamRuby attachment_name = claimed_recording.name end - puts "ATTACMENT #{}" - msg = @@message_factory.chat_message( music_session_id, diff --git a/ruby/lib/jam_ruby/models/lesson_session.rb b/ruby/lib/jam_ruby/models/lesson_session.rb index 8e70af29e..a41f248bc 100644 --- a/ruby/lib/jam_ruby/models/lesson_session.rb +++ b/ruby/lib/jam_ruby/models/lesson_session.rb @@ -116,16 +116,15 @@ module JamRuby end 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 - @@log.debug("analysis lesson session #{lession_session.id}") lession_session.analyse end end def self.complete_sessions # 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.session_completed end diff --git a/web/app/assets/javascripts/react-components/InLessonBroadcast.js.jsx.coffee b/web/app/assets/javascripts/react-components/InLessonBroadcast.js.jsx.coffee index cccbe2b29..379cb69a1 100644 --- a/web/app/assets/javascripts/react-components/InLessonBroadcast.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/InLessonBroadcast.js.jsx.coffee @@ -43,6 +43,14 @@ context = window timeString 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.success content = `
@@ -61,18 +69,19 @@ context = window content = `

You need to wait in this session for

{this.displayTime()}

-

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.

+

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}.

` else if @props.lessonSession.teacherFault - if @props.lessonSession.teacherPresent? + if @props.lessonSession.isStudent content = `
-

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.

-

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.

+

You may now leave the session.

+

Your teacher will be marked absent and penalized for missing the lesson. You will not be charged for this lesson.

+

We apologize for your inconvenience, and we will work to remedy this situation.

` else content = `

You may now leave the session.

-

Your teacher will be marked absent and penalized for missing the lesson. You will not be charged for this lesson.

+

Your student will be marked absent and penalized for missing the lesson. You will still received payment for this lesson.

We apologize for your inconvenience, and we will work to remedy this situation.

` diff --git a/web/app/assets/javascripts/react-components/JamClassScreen.js.jsx.coffee b/web/app/assets/javascripts/react-components/JamClassScreen.js.jsx.coffee index 99f1ac078..8e733943d 100644 --- a/web/app/assets/javascripts/react-components/JamClassScreen.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/JamClassScreen.js.jsx.coffee @@ -105,13 +105,13 @@ LessonTimerActions = context.LessonTimerActions title: 'Start Time Set', 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({ id: lessonId, - minutes: -35 + minutes: -65 }).done((response) => (@app.layout.notify({ 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' window.location.href = "/client#/jamclass/lesson-payment/lesson-booking_#{lessonId}" diff --git a/web/app/assets/javascripts/react-components/LessonBookingDecision.js.jsx.coffee b/web/app/assets/javascripts/react-components/LessonBookingDecision.js.jsx.coffee index 49fcfab49..a744c9cea 100644 --- a/web/app/assets/javascripts/react-components/LessonBookingDecision.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/LessonBookingDecision.js.jsx.coffee @@ -177,7 +177,7 @@ :
- * Time will be local to {context.JK.currentTimezone()} + * Time will be local to {window.JK.currentTimezone()} {errorText} @@ -199,7 +199,7 @@ :
- *Time will be local to {context.JK.currentTimezone()} + *Time will be local to {window.JK.currentTimezone()} {errorText}
` diff --git a/web/app/assets/javascripts/react-components/TeacherSearchScreen.js.jsx.coffee b/web/app/assets/javascripts/react-components/TeacherSearchScreen.js.jsx.coffee index 904b517c0..5e336f9be 100644 --- a/web/app/assets/javascripts/react-components/TeacherSearchScreen.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/TeacherSearchScreen.js.jsx.coffee @@ -38,7 +38,7 @@ ProfileActions = @ProfileActions afterShow: (e) -> UserActions.refresh() - + #@setState(TeacherSearchStore.getState()) #if @state.results.length == 0 # don't issue a new search every time someone comes to the screen, to preserve location from previous browsing diff --git a/web/app/assets/javascripts/react-components/stores/BroadcastStore.js.coffee b/web/app/assets/javascripts/react-components/stores/BroadcastStore.js.coffee index 53dacfdf9..1d5968687 100644 --- a/web/app/assets/javascripts/react-components/stores/BroadcastStore.js.coffee +++ b/web/app/assets/javascripts/react-components/stores/BroadcastStore.js.coffee @@ -93,7 +93,7 @@ BroadcastStore = Reflux.createStore( @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 @@ -137,9 +137,13 @@ BroadcastStore = Reflux.createStore( changed: () -> if @currentLesson? + @currentLesson.isStudent == @currentLesson.student_id == context.JK.currentUserId + @currentLesson.isTeacher = !@currentLesson.isStudent @currentLesson.teacherFault = @teacherFault @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) else this.trigger(@currentLesson) diff --git a/web/app/assets/javascripts/react-components/stores/SessionStore.js.coffee b/web/app/assets/javascripts/react-components/stores/SessionStore.js.coffee index bd2447424..95ffeb0b5 100644 --- a/web/app/assets/javascripts/react-components/stores/SessionStore.js.coffee +++ b/web/app/assets/javascripts/react-components/stores/SessionStore.js.coffee @@ -774,7 +774,6 @@ ConfigureTracksActions = @ConfigureTracksActions context.JK.JamServer.registerMessageCallback(context.JK.MessageType.TRACKS_CHANGED, @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 @handleAutoOpenJamTrack() diff --git a/web/app/views/clients/_lessonSessionActions.html.slim b/web/app/views/clients/_lessonSessionActions.html.slim index c42b76c35..9e0a4fc18 100644 --- a/web/app/views/clients/_lessonSessionActions.html.slim +++ b/web/app/views/clients/_lessonSessionActions.html.slim @@ -64,8 +64,8 @@ script type='text/template' id='template-lesson-session-actions' = '{% if (data.isAdmin) { %}' li data-lesson-option="start-5-min" a href='#' Set Start In 5 Min - li data-lesson-option="start-35-ago" - a href='#' Set Start 35 Min Ago + li data-lesson-option="start-65-ago" + a href='#' Set Start 65 Min Ago = '{% } %}' = '{% } else { %}' diff --git a/web/lib/tasks/lesson.rake b/web/lib/tasks/lesson.rake index a2963c3ab..99fdd999f 100644 --- a/web/lib/tasks/lesson.rake +++ b/web/lib/tasks/lesson.rake @@ -1,10 +1,39 @@ require 'factory_girl' +require 'timecop' +require 'rspec-rails' +require Rails.root.join('spec', 'support', 'lessons.rb') 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| - user = User.find_by_email(ENV['STUDENT_EMAIL']) - teacher = User.find_by_email(ENV['TEACHER_EMAIL']) + user = User.find_by_email(ENV['STUDENT']) + teacher = User.find_by_email(ENV['TEACHER']) recurring = ENV['RECURRING'] == '1' slots = [] @@ -71,7 +100,7 @@ namespace :lessons do lesson = booking.lesson_sessions[0] 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 #lesson.accept({message: 'Yeah I got this', slot: slots[0]}) @@ -80,6 +109,6 @@ namespace :lessons do #lesson.slot.should eql slots[0] #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 diff --git a/web/spec/support/lessons.rb b/web/spec/support/lessons.rb index 3fed2208e..533ee3055 100644 --- a/web/spec/support/lessons.rb +++ b/web/spec/support/lessons.rb @@ -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? options[:package_count] = 4 end + if options[:slots].nil? - slots = [] - slots << FactoryGirl.build(:lesson_booking_slot_single) - slots << FactoryGirl.build(:lesson_booking_slot_single) + slots = [] + if options[:monthly] + 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 slots = options[:slots] end - if user.stored_credit_card == false - user.stored_credit_card = true - user.save! + token = create_stripe_token + result = user.payment_update({token: token, zip: '78759', normal: true}) + #user.stored_credit_card = true + #user.save! 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? puts "BOOKING #{booking.errors.inspect}" + + if booking.lesson_booking_slots[0].errors.any? + puts "SLOT0 #{booking.lesson_booking_slots[0].errors.inspect}" + end end - booking.errors.any?.should be_false + + booking.errors.any?.should be_false unless options[:no_validate] + lesson = booking.lesson_sessions[0] start = lesson.scheduled_start 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? - LessonPackagePurchase.create(user, booking, LessonPackageType.package_for_test_drive_count(options[:package_count])) + if options[:test_drive] + if user.most_recent_test_drive_purchase.nil? + LessonPackagePurchase.create(user, booking, LessonPackageType.package_for_test_drive_count(options[:package_count])) + end end + if options[:accept] 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.slot.should eql slots[0] - lesson.status.should eql LessonSession::STATUS_APPROVED + lesson.slot.should eql slots[0] unless options[:no_validate] + lesson.status.should eql LessonSession::STATUS_APPROVED unless options[:no_validate] end if options[:cancel] lesson.cancel({canceler: options[:canceler] || user, message: "sorry about that"}) lesson.reload - lesson.status.should eql LessonSession::STATUS_CANCELED + lesson.status.should eql LessonSession::STATUS_CANCELED unless options[:no_validate] end 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.session_completed + elsif options[:finish] # 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) + 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 lesson.music_session.session_removed_at = end_time lesson.music_session.save! + Timecop.travel(end_time + 1) + + lesson.analyse lesson.session_completed + + if options[:monthly] + LessonBooking.hourly_check + end end lesson end - - -def normal_lesson(user, teacher, slots = nil) - - 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 +def testdrive_lesson(user, teacher, options = {finish: false, accept: true, cancel: false, miss: false, slots: nil}) + options[:test_drive] = true + book_lesson(user, teacher, options) end -def monthly_lesson(user, teacher, slots = nil) - - if slots.nil? - 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 +def normal_lesson(user, teacher, options = {finish: false, accept: true, cancel: false, miss: false, slots: nil}) + options[:normal] = true + book_lesson(user, teacher, options) 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 \ No newline at end of file