Merge branch 'develop' of bitbucket.org:jamkazam/jam-cloud into develop
This commit is contained in:
commit
481bc36133
|
|
@ -73,7 +73,7 @@ gem 'iso-639'
|
|||
gem 'rubyzip'
|
||||
gem 'sanitize'
|
||||
gem 'slim'
|
||||
gem 'influxdb'
|
||||
#gem 'influxdb'
|
||||
gem 'cause' # needed by influxdb
|
||||
gem 'influxdb-rails', '0.1.10'
|
||||
gem 'recurly'
|
||||
|
|
@ -107,7 +107,6 @@ end
|
|||
group :development, :test do
|
||||
gem 'capybara'
|
||||
gem 'rspec-rails', '2.14.2'
|
||||
gem 'guard-rspec'
|
||||
gem 'jasmine', '1.3.1'
|
||||
gem 'execjs', '1.4.0'
|
||||
#gem 'therubyracer' #, '0.11.0beta8'
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
ActiveAdmin.register JamRuby::User, :as => 'SchoolInterest' do
|
||||
|
||||
menu :label => 'Interested in Schools', :parent => 'JamClass'
|
||||
|
||||
config.sort_order = 'created_at desc'
|
||||
config.batch_actions = false
|
||||
config.per_page = 100
|
||||
config.paginate = true
|
||||
config.filters = false
|
||||
|
||||
scope("All", default: true) { |scope| scope.where(school_interest: true) }
|
||||
|
||||
index do
|
||||
column "Name" do |user|
|
||||
span do
|
||||
link_to "#{user.name} (#{user.email})", "#{Rails.application.config.external_root_url}/client#/profile/#{user.id}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -6,12 +6,13 @@ ActiveAdmin.register JamRuby::User, :as => 'Students' do
|
|||
config.batch_actions = false
|
||||
config.per_page = 100
|
||||
config.paginate = true
|
||||
config.filters = false
|
||||
|
||||
def booked_anything(scope)
|
||||
def booked_anything(scope)
|
||||
scope.joins(:student_lesson_bookings).where('lesson_bookings.active = true').uniq
|
||||
end
|
||||
|
||||
scope("Default", default: true) { |scope| booked_anything(scope).order('ready_for_session_at IS NULL DESC') }
|
||||
scope("Default", default: true) { |scope| scope.where('is_a_student = true OR ((select count(id) from lesson_bookings where lesson_bookings.user_id = users.id) > 0)').order('users.ready_for_session_at IS NULL DESC') }
|
||||
|
||||
index do
|
||||
column "Name" do |user|
|
||||
|
|
@ -45,8 +46,8 @@ ActiveAdmin.register JamRuby::User, :as => 'Students' do
|
|||
end
|
||||
end
|
||||
column "School" do |user|
|
||||
if teacher.school
|
||||
teacher.school.name
|
||||
if user.school
|
||||
user.school.name
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
ActiveAdmin.register JamRuby::Teacher, :as => 'Teachers' do
|
||||
|
||||
menu :label => 'Teacher', :parent => 'JamClass'
|
||||
menu :label => 'Teachers', :parent => 'JamClass'
|
||||
|
||||
config.sort_order = 'created_at desc'
|
||||
config.batch_actions = false
|
||||
|
|
|
|||
|
|
@ -1,18 +1,21 @@
|
|||
GEM
|
||||
remote: http://rubygems.org/
|
||||
specs:
|
||||
little-plugger (1.1.3)
|
||||
little-plugger (1.1.4)
|
||||
logging (1.7.2)
|
||||
little-plugger (>= 1.1.3)
|
||||
pg (0.17.1)
|
||||
pg_migrate (0.1.13)
|
||||
pg_migrate (0.1.14)
|
||||
logging (= 1.7.2)
|
||||
pg (= 0.17.1)
|
||||
thor
|
||||
thor (0.18.1)
|
||||
thor (0.19.1)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
pg_migrate (= 0.1.13)!
|
||||
pg_migrate (= 0.1.14)!
|
||||
|
||||
BUNDLED WITH
|
||||
1.11.2
|
||||
|
|
|
|||
|
|
@ -341,4 +341,10 @@ email_blacklist.sql
|
|||
jamblaster_connection.sql
|
||||
teacher_progression.sql
|
||||
teacher_complete.sql
|
||||
lessons.sql
|
||||
lessons.sql
|
||||
lessons_unread_messages.sql
|
||||
track_school_signups.sql
|
||||
add_test_drive_types.sql
|
||||
updated_subjects.sql
|
||||
update_payment_history.sql
|
||||
lesson_booking_schools.sql
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
INSERT INTO lesson_package_types (id, name, description, package_type, price) VALUES ('test-drive-2', 'Test Drive (2)', 'Two reduced-price lessons which you can use to find that ideal teacher.', 'test-drive-2', 29.99);
|
||||
INSERT INTO lesson_package_types (id, name, description, package_type, price) VALUES ('test-drive-1', 'Test Drive (1)', 'One reduced-price lessons which you can use to find that ideal teacher.', 'test-drive-1', 15.99);
|
||||
UPDATE lesson_package_types set name = 'Test Drive (4)', package_type = 'test-drive-4' WHERE id = 'test-drive';
|
||||
ALTER TABLE users ADD COLUMN lesson_package_type_id VARCHAR(64) REFERENCES lesson_package_types(id);
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
ALTER TABLE lesson_bookings ADD COLUMN school_id INTEGER REFERENCES schools(id);
|
||||
ALTER TABLE teacher_payments ADD COLUMN school_id INTEGER REFERENCES schools(id);
|
||||
ALTER TABLE teacher_distributions ADD COLUMN school_id INTEGER REFERENCES schools(id);
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
ALTER TABLE chat_messages DROP COLUMN lesson_booking_id;
|
||||
ALTER TABLE chat_messages ADD COLUMN lesson_session_id VARCHAR(64) REFERENCES lesson_sessions(id);
|
||||
ALTER TABLE lesson_sessions ADD COLUMN teacher_unread_messages BOOLEAN DEFAULT FALSE NOT NULL;
|
||||
ALTER TABLE lesson_sessions ADD COLUMN student_unread_messages BOOLEAN DEFAULT FALSE NOT NULL;
|
||||
ALTER TABLE chat_messages ADD COLUMN purpose VARCHAR(200);
|
||||
ALTER TABLE lesson_sessions ADD COLUMN student_short_canceled BOOLEAN DEFAULT FALSE NOT NULL;
|
||||
ALTER TABLE lesson_sessions ADD COLUMN teacher_short_canceled BOOLEAN DEFAULT FALSE NOT NULL;
|
||||
ALTER TABLE lesson_sessions ADD COLUMN sent_starting_notice BOOLEAN DEFAULT FALSE NOT NULL;
|
||||
|
||||
ALTER TABLE lesson_bookings DROP CONSTRAINT lesson_bookings_counter_slot_id_fkey;
|
||||
ALTER TABLE lesson_bookings ADD CONSTRAINT lesson_bookings_counter_slot_id_fkey FOREIGN KEY (counter_slot_id) REFERENCES lesson_booking_slots(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE lesson_bookings DROP CONSTRAINT lesson_bookings_default_slot_id_fkey;
|
||||
ALTER TABLE lesson_bookings ADD CONSTRAINT lesson_bookings_default_slot_id_fkey FOREIGN KEY (default_slot_id) REFERENCES lesson_booking_slots(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
ALTER TABLE lesson_sessions DROP CONSTRAINT lesson_sessions_slot_id_fkey;
|
||||
ALTER TABLE lesson_sessions ADD CONSTRAINT lesson_sessions_slot_id_fkey FOREIGN KEY (slot_id) REFERENCES lesson_booking_slots(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE users DROP CONSTRAINT users_teacher_id_fkey;
|
||||
ALTER TABLE users ADD CONSTRAINT users_teacher_id_fkey FOREIGN KEY (teacher_id) REFERENCES teachers(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE music_sessions DROP CONSTRAINT music_sessions_lesson_session_id_fkey;
|
||||
ALTER TABLE music_sessions ADD CONSTRAINT music_sessions_lesson_session_id_fkey FOREIGN KEY (lesson_session_id) REFERENCES lesson_sessions(id) ON DELETE SET NULL;
|
||||
|
||||
ALTER TABLE notifications DROP CONSTRAINT notifications_lesson_session_id_fkey;
|
||||
ALTER TABLE notifications ADD CONSTRAINT notifications_lesson_session_id_fkey FOREIGN KEY (lesson_session_id) REFERENCES lesson_sessions(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE chat_messages DROP CONSTRAINT chat_messages_lesson_session_id_fkey;
|
||||
ALTER TABLE chat_messages ADD CONSTRAINT chat_messages_lesson_session_id_fkey FOREIGN KEY (lesson_session_id) REFERENCES lesson_sessions(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE chat_messages DROP CONSTRAINT chat_messages_target_user_id_fkey;
|
||||
ALTER TABLE chat_messages ADD CONSTRAINT chat_messages_target_user_id_fkey FOREIGN KEY (lesson_session_id) REFERENCES lesson_sessions(id) ON DELETE SET NULL;
|
||||
|
||||
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE USERS ADD COLUMN school_interest BOOLEAN DEFAULT FALSE;
|
||||
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE charges ADD COLUMN user_id VARCHAR(64) REFERENCES users(id);
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
-- https://jamkazam.atlassian.net/browse/VRFS-3407
|
||||
UPDATE subjects SET description = 'Composition' WHERE id = 'composing';
|
||||
UPDATE subjects SET description = 'Recording & Production' WHERE id = 'recording';
|
||||
UPDATE subjects SET description = 'Sight Reading' WHERE id = 'site-reading';
|
||||
|
||||
INSERT INTO subjects(id, description) VALUES ('film-scoring', 'Film Scoring');
|
||||
INSERT INTO subjects(id, description) VALUES ('video-game-scoring', 'Video Game Scoring');
|
||||
INSERT INTO subjects(id, description) VALUES ('ear-training', 'Ear Training');
|
||||
INSERT INTO subjects(id, description) VALUES ('harmony', 'Harmony');
|
||||
INSERT INTO subjects(id, description) VALUES ('music-therapy', 'Music Therapy');
|
||||
INSERT INTO subjects(id, description) VALUES ('songwriting', 'Songwriting');
|
||||
INSERT INTO subjects(id, description) VALUES ('conducting', 'Conducting');
|
||||
INSERT INTO subjects(id, description) VALUES ('instrument-repair', 'Instrument Repair');
|
||||
INSERT INTO subjects(id, description) VALUES ('improvisation', 'Improvisation');
|
||||
INSERT INTO subjects(id, description) VALUES ('pro-tools', 'Pro Tools');
|
||||
INSERT INTO subjects(id, description) VALUES ('ableton-live', 'Ableton Live');
|
||||
INSERT INTO subjects(id, description) VALUES ('fl-studio', 'FL Studio');
|
||||
INSERT INTO subjects(id, description) VALUES ('garageband', 'GarageBand');
|
||||
INSERT INTO subjects(id, description) VALUES ('apple-logic-pro', 'Apple Logic Pro');
|
||||
INSERT INTO subjects(id, description) VALUES ('presonus-studio-one', 'PreSonus Studio One');
|
||||
INSERT INTO subjects(id, description) VALUES ('reaper', 'Reaper');
|
||||
INSERT INTO subjects(id, description) VALUES ('cubase', 'Cubase');
|
||||
INSERT INTO subjects(id, description) VALUES ('sonar', 'Sonar');
|
||||
INSERT INTO subjects(id, description) VALUES ('reason', 'Reason');
|
||||
INSERT INTO subjects(id, description) VALUES ('amplitube', 'AmpliTube');
|
||||
INSERT INTO subjects(id, description) VALUES ('line-6-pod', 'Line 6 Pod');
|
||||
INSERT INTO subjects(id, description) VALUES ('guitar-ring', 'Guitar Rig');
|
||||
|
|
@ -619,6 +619,8 @@ message ChatMessage {
|
|||
optional string msg_id = 4;
|
||||
optional string created_at = 5;
|
||||
optional string channel = 6;
|
||||
optional string lesson_session_id = 7;
|
||||
optional string purpose = 8;
|
||||
}
|
||||
|
||||
message SendChatMessage {
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ gem 'rest-client'
|
|||
gem 'iso-639'
|
||||
gem 'rubyzip'
|
||||
gem 'sanitize'
|
||||
gem 'influxdb'
|
||||
#gem 'influxdb'
|
||||
gem 'recurly'
|
||||
gem 'sendgrid_toolkit', '>= 1.1.1'
|
||||
gem 'stripe'
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ require "jam_ruby/resque/scheduled/unused_music_notation_cleaner"
|
|||
require "jam_ruby/resque/scheduled/user_progress_emailer"
|
||||
require "jam_ruby/resque/scheduled/daily_job"
|
||||
require "jam_ruby/resque/scheduled/hourly_job"
|
||||
require "jam_ruby/resque/scheduled/minutely_job"
|
||||
require "jam_ruby/resque/scheduled/daily_session_emailer"
|
||||
require "jam_ruby/resque/scheduled/new_musician_emailer"
|
||||
require "jam_ruby/resque/scheduled/music_session_reminder"
|
||||
|
|
|
|||
|
|
@ -36,6 +36,14 @@ module JamRuby
|
|||
subject: options[:subject])
|
||||
end
|
||||
|
||||
def partner(options)
|
||||
mail(to: APP_CONFIG.email_partners_alias,
|
||||
from: APP_CONFIG.email_generic_from,
|
||||
body: options[:body],
|
||||
content_type: "text/plain",
|
||||
subject: options[:subject])
|
||||
end
|
||||
|
||||
def recurly_alerts(user, options)
|
||||
|
||||
body = options[:body]
|
||||
|
|
|
|||
|
|
@ -81,6 +81,22 @@ module JamRuby
|
|||
end
|
||||
end
|
||||
|
||||
def school_owner_welcome_message(user)
|
||||
@user = user
|
||||
@subject= "Welcome to JamKazam and JamClass online lessons!"
|
||||
sendgrid_category "Welcome"
|
||||
sendgrid_unique_args :type => "welcome_message"
|
||||
|
||||
sendgrid_recipients([user.email])
|
||||
sendgrid_substitute('@USERID', [user.id])
|
||||
sendgrid_substitute(EmailBatchProgression::VAR_FIRST_NAME, [user.first_name])
|
||||
|
||||
mail(:to => user.email, :subject => @subject) do |format|
|
||||
format.text
|
||||
format.html
|
||||
end
|
||||
end
|
||||
|
||||
def password_changed(user)
|
||||
@user = user
|
||||
|
||||
|
|
@ -912,7 +928,7 @@ module JamRuby
|
|||
@lesson_session = lesson_session
|
||||
|
||||
email = @student.email
|
||||
subject = "You have used #{@student.remaining_test_drives} of 4 TestDrive lesson credits"
|
||||
subject = "You have used #{@student.remaining_test_drives} of #{@student.total_test_drives} TestDrive lesson credits"
|
||||
unique_args = {:type => "student_test_drive_success"}
|
||||
|
||||
sendgrid_category "Notification"
|
||||
|
|
@ -927,6 +943,31 @@ module JamRuby
|
|||
end
|
||||
end
|
||||
|
||||
def student_test_drive_no_bill(lesson_session)
|
||||
@student = lesson_session.student
|
||||
@teacher = lesson_session.teacher
|
||||
@session_name = lesson_session.music_session.name
|
||||
@session_description = lesson_session.music_session.description
|
||||
@session_date = lesson_session.slot.pretty_scheduled_start(true)
|
||||
@session_url = lesson_session.web_url
|
||||
@lesson_session = lesson_session
|
||||
|
||||
email = @student.email
|
||||
subject = "Your TestDrive with #{@teacher.name} will not be billed"
|
||||
unique_args = {:type => "student_test_drive_no_bill"}
|
||||
|
||||
sendgrid_category "Notification"
|
||||
sendgrid_unique_args :type => unique_args[:type]
|
||||
|
||||
sendgrid_recipients([email])
|
||||
sendgrid_substitute('@USERID', [@student.id])
|
||||
|
||||
mail(:to => email, :subject => subject) do |format|
|
||||
format.text
|
||||
format.html { render :layout => "from_user_mailer" }
|
||||
end
|
||||
end
|
||||
|
||||
# successfully completed, but no more test drives left
|
||||
def student_test_drive_lesson_done(lesson_session)
|
||||
|
||||
|
|
@ -939,7 +980,7 @@ module JamRuby
|
|||
@lesson_session = lesson_session
|
||||
|
||||
email = @student.email
|
||||
subject = "You have used all 4 TestDrive lesson credits"
|
||||
subject = "You have used all TestDrive lesson credits"
|
||||
unique_args = {:type => "student_test_drive_success"}
|
||||
|
||||
sendgrid_category "Notification"
|
||||
|
|
@ -1229,12 +1270,39 @@ module JamRuby
|
|||
end
|
||||
end
|
||||
|
||||
# always goes to the teacher
|
||||
def teacher_distribution_done(teacher_payment)
|
||||
@school = teacher_payment.school
|
||||
@teacher_payment = teacher_payment
|
||||
@distribution = teacher_payment.teacher_distribution
|
||||
@teacher = teacher_payment.teacher
|
||||
@payable_teacher = teacher_payment.payable_teacher
|
||||
@name = @teacher.first_name || 'Anonymous'
|
||||
@student = @distribution.student
|
||||
email = @teacher.email
|
||||
|
||||
@subject = "You have received payment for your participation in JamClass"
|
||||
if @school
|
||||
if @distribution.is_test_drive?
|
||||
@subject = "Your TestDrive lesson with #{@student.name}"
|
||||
elsif @distribution.is_normal?
|
||||
@subject = "Your lesson with #{@student.name}"
|
||||
elsif @distribution.is_monthly?
|
||||
@subject = "Your #{@distribution.month_name} lessons with #{@student.name}"
|
||||
else
|
||||
@subject = "Your lesson with #{@student.name}"
|
||||
end
|
||||
else
|
||||
if @distribution.is_test_drive?
|
||||
@subject = "You have earned #{@distribution.real_distribution_display} for your TestDrive lesson with #{@student.first_name}"
|
||||
elsif @distribution.is_normal?
|
||||
@subject = "You have earned #{@distribution.real_distribution_display} for your lesson with #{@student.first_name}"
|
||||
elsif @distribution.is_monthly?
|
||||
@subject = "You have earned #{@distribution.real_distribution_display} for your #{@distribution.month_name} lessons with #{@student.first_name}"
|
||||
else
|
||||
@subject = "You have earned #{@distribution.real_distribution_display} for your lesson with #{@student.first_name}"
|
||||
end
|
||||
end
|
||||
|
||||
unique_args = {:type => "teacher_distribution_done"}
|
||||
|
||||
sendgrid_category "Notification"
|
||||
|
|
@ -1249,24 +1317,51 @@ module JamRuby
|
|||
end
|
||||
end
|
||||
|
||||
# if school, goes to school owner; otherwise goes to teacher
|
||||
def teacher_distribution_fail(teacher_payment)
|
||||
@school = teacher_payment.school
|
||||
@teacher_payment = teacher_payment
|
||||
@distribution = teacher_payment.teacher_distribution
|
||||
@teacher = teacher_payment.teacher
|
||||
email = @teacher.email
|
||||
@payable_teacher = teacher_payment.payable_teacher
|
||||
@student = @distribution.student
|
||||
@name = @payable_teacher.first_name || 'Anonymous'
|
||||
email = @payable_teacher.email
|
||||
|
||||
@card_declined = teacher_payment.is_card_declined?
|
||||
@card_expired = teacher_payment.is_card_expired?
|
||||
@bill_date = teacher_payment.last_billed_at_date
|
||||
|
||||
|
||||
@subject = "We were unable to pay you today"
|
||||
if @school
|
||||
if @distribution.is_test_drive?
|
||||
@subject = "We had a problem paying #{@distribution.real_distribution_display} for #{@teacher.name}'s TestDrive lesson with #{@student.name}"
|
||||
elsif @distribution.is_normal?
|
||||
@subject = "We had a problem paying #{@distribution.real_distribution_display} for #{@teacher.name}'s lesson with #{@student.name}"
|
||||
elsif @distribution.is_monthly?
|
||||
@subject = "We had a problem paying #{@distribution.real_distribution_display} for #{@teacher.name}'s #{@distribution.month_name} lessons with #{@student.name}"
|
||||
else
|
||||
@subject = "We had a problem paying #{@distribution.real_distribution_display} for #{@teacher.name}'s lesson with #{@student.name}"
|
||||
end
|
||||
else
|
||||
if @distribution.is_test_drive?
|
||||
@subject = "We had a problem paying you #{@distribution.real_distribution_display} for your TestDrive lesson with #{@student.first_name}"
|
||||
elsif @distribution.is_normal?
|
||||
@subject = "We had a problem paying you #{@distribution.real_distribution_display} for your lesson with #{@student.first_name}"
|
||||
elsif @distribution.is_monthly?
|
||||
@subject = "We had a problem paying you #{@distribution.real_distribution_display} for your #{@distribution.month_name} lessons with #{@student.first_name}"
|
||||
else
|
||||
@subject = "We had a problem paying you #{@distribution.real_distribution_display} for your lesson with #{@student.first_name}"
|
||||
end
|
||||
end
|
||||
|
||||
unique_args = {:type => "teacher_distribution_fail"}
|
||||
|
||||
sendgrid_category "Notification"
|
||||
sendgrid_unique_args :type => unique_args[:type]
|
||||
|
||||
sendgrid_recipients([email])
|
||||
sendgrid_substitute('@USERID', [@teacher.id])
|
||||
sendgrid_substitute('@USERID', [@payable_teacher.id])
|
||||
|
||||
mail(:to => email, :subject => @subject) do |format|
|
||||
format.text
|
||||
|
|
@ -1274,6 +1369,42 @@ module JamRuby
|
|||
end
|
||||
end
|
||||
|
||||
# always goes to the school owner
|
||||
def school_distribution_done(teacher_payment)
|
||||
@school = teacher_payment.school
|
||||
@teacher_payment = teacher_payment
|
||||
@distribution = teacher_payment.teacher_distribution
|
||||
@teacher = teacher_payment.teacher
|
||||
@payable_teacher = @school.owner
|
||||
@name = @payable_teacher.first_name || 'Anonymous'
|
||||
@student = @distribution.student
|
||||
email = @payable_teacher.email
|
||||
|
||||
if @distribution.is_test_drive?
|
||||
@subject = "#{@teacher.name} has earned #{@distribution.real_distribution_display} for TestDrive lesson with #{@student.name}"
|
||||
elsif @distribution.is_normal?
|
||||
@subject = "#{@teacher.name} has earned #{@distribution.real_distribution_display} for a lesson with #{@student.name}"
|
||||
elsif @distribution.is_monthly?
|
||||
@subject = "#{@teacher.name} has earned #{@distribution.real_distribution_display} for #{@distribution.month_name} lessons with #{@student.name}"
|
||||
else
|
||||
@subject = "#{@teacher.name} has earned #{@distribution.real_distribution_display} for a lesson with #{@student.name}"
|
||||
end
|
||||
|
||||
unique_args = {:type => "school_distribution_done"}
|
||||
|
||||
sendgrid_category "Notification"
|
||||
sendgrid_unique_args :type => unique_args[:type]
|
||||
|
||||
sendgrid_recipients([email])
|
||||
sendgrid_substitute('@USERID', [@payable_teacher.id])
|
||||
|
||||
mail(:to => email, :subject => @subject) do |format|
|
||||
format.text
|
||||
format.html
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def monthly_recurring_done(lesson_session)
|
||||
@student = lesson_session.student
|
||||
@teacher = lesson_session.teacher
|
||||
|
|
@ -1485,5 +1616,78 @@ module JamRuby
|
|||
format.html
|
||||
end
|
||||
end
|
||||
|
||||
def lesson_chat(chat_msg)
|
||||
@target = chat_msg.target_user
|
||||
@sender = chat_msg.user
|
||||
@message = chat_msg.message
|
||||
@lesson_session = chat_msg.lesson_session
|
||||
@session_name = @lesson_session.music_session.name
|
||||
@session_description = @lesson_session.music_session.description
|
||||
@session_date = @lesson_session.slot.pretty_scheduled_start(true)
|
||||
|
||||
email = @target.email
|
||||
@subject = "#{@sender.name} has sent you a message about a lesson"
|
||||
unique_args = {:type => "lesson_chat"}
|
||||
|
||||
sendgrid_category "Notification"
|
||||
sendgrid_unique_args :type => unique_args[:type]
|
||||
sendgrid_recipients([email])
|
||||
sendgrid_substitute('@USERID', [@target.id])
|
||||
|
||||
mail(:to => email, :subject => @subject) do |format|
|
||||
format.text
|
||||
format.html { render :layout => "from_user_mailer" }
|
||||
end
|
||||
end
|
||||
|
||||
def lesson_starting_soon_teacher(lesson_session)
|
||||
@lesson_booking = lesson_booking = lesson_session.lesson_booking
|
||||
@student = lesson_booking.student
|
||||
@teacher = lesson_booking.teacher
|
||||
@lesson_session = lesson_booking.next_lesson
|
||||
@session_name = @lesson_session.music_session.name
|
||||
@session_description = @lesson_session.music_session.description
|
||||
@session_date = @lesson_session.slot.pretty_scheduled_start(true)
|
||||
|
||||
email = @teacher.email
|
||||
@subject = "Your lesson with #{@student.first_name} on JamKazam is starting soon"
|
||||
unique_args = {:type => "send_starting_notice_teacher"}
|
||||
|
||||
sendgrid_category "Notification"
|
||||
sendgrid_unique_args :type => unique_args[:type]
|
||||
sendgrid_recipients([email])
|
||||
sendgrid_substitute('@USERID', [@teacher.id])
|
||||
|
||||
mail(:to => email, :subject => @subject) do |format|
|
||||
format.text
|
||||
format.html { render :layout => "from_user_mailer" }
|
||||
end
|
||||
end
|
||||
|
||||
def lesson_starting_soon_student(lesson_session)
|
||||
@lesson_booking = lesson_booking = lesson_session.lesson_booking
|
||||
@student = lesson_booking.student
|
||||
@teacher = lesson_booking.teacher
|
||||
@message = message
|
||||
@lesson_session = lesson_booking.next_lesson
|
||||
@session_name = @lesson_session.music_session.name
|
||||
@session_description = @lesson_session.music_session.description
|
||||
@session_date = @lesson_session.slot.pretty_scheduled_start(true)
|
||||
|
||||
email = @student.email
|
||||
@subject = "Your lesson with #{@student.first_name} on JamKazam is starting soon"
|
||||
unique_args = {:type => "send_starting_notice_student"}
|
||||
|
||||
sendgrid_category "Notification"
|
||||
sendgrid_unique_args :type => unique_args[:type]
|
||||
sendgrid_recipients([email])
|
||||
sendgrid_substitute('@USERID', [@student.id])
|
||||
|
||||
mail(:to => email, :subject => @subject) do |format|
|
||||
format.text
|
||||
format.html { render :layout => "from_user_mailer" }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
<% provide(:title, @subject) %>
|
||||
<% provide(:photo_url, @sender.resolved_photo_url) %>
|
||||
|
||||
<% content_for :note do %>
|
||||
<p>
|
||||
|
||||
<% if @message.present? %>
|
||||
<br/><br/><%= @sender.name %> says:
|
||||
<br/><%= @message %>
|
||||
<br/>
|
||||
<% end %>
|
||||
<br/><br/>Click the button below to view the entire lesson conversation.</p>
|
||||
<p>
|
||||
<a href="<%= @lesson_session.chat_url %>" style="margin: 8px 0 0 0;background-color: #ed3618;border: solid 1px #F27861;padding: 3px 10px;font-size: 12px;font-weight: 300;cursor: pointer;color: #FC9;text-decoration: none;line-height: 12px;text-align: center;">VIEW LESSON CONVERSATION</a>
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<%= @subject %>
|
||||
|
||||
<%= @sender.name %> says:
|
||||
|
||||
<%= @message %>
|
||||
|
||||
To see the full lesson conversation, click here: <%= @lesson_session.chat_url %>
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<% provide(:title, @subject) %>
|
||||
<% provide(:photo_url, @teacher.resolved_photo_url) %>
|
||||
|
||||
<% content_for :note do %>
|
||||
<p>
|
||||
Your lesson with <%= @teacher.name %> is scheduled to begin on JamKazam in less than 30 minutes.
|
||||
<p>
|
||||
<a href="<%= @lesson_session.home_url %>" style="margin: 8px 0 0 0;background-color: #ed3618;border: solid 1px #F27861;padding: 3px 10px;font-size: 12px;font-weight: 300;cursor: pointer;color: #FC9;text-decoration: none;line-height: 12px;text-align: center;">JAMCLASS HOME</a>
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
Your lesson with <%= @teacher.name %> is scheduled to begin on JamKazam in less than 30 minutes.
|
||||
|
||||
JAMCLASS HOME (<%= @lesson_session.home_url %>
|
||||
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<% provide(:title, @subject) %>
|
||||
<% provide(:photo_url, @student.resolved_photo_url) %>
|
||||
|
||||
<% content_for :note do %>
|
||||
<p>
|
||||
Your lesson with <%= @student.name %> is scheduled to begin on JamKazam in less than 30 minutes.
|
||||
<p>
|
||||
<a href="<%= @lesson_session.home_url %>" style="margin: 8px 0 0 0;background-color: #ed3618;border: solid 1px #F27861;padding: 3px 10px;font-size: 12px;font-weight: 300;cursor: pointer;color: #FC9;text-decoration: none;line-height: 12px;text-align: center;">JAMCLASS HOME</a>
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
Your lesson with <%= @student.name %> is scheduled to begin on JamKazam in less than 30 minutes.
|
||||
JAMCLASS HOME (<%= @lesson_session.home_url %>
|
||||
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
</p>
|
||||
|
||||
<p>
|
||||
We hope you enjoyed your JamClass lesson today with <%= @teacher.name %>. As just a reminder, you already paid for this lesson in advance.
|
||||
We hope you enjoyed your JamClass lesson today with <%= @teacher.name %>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
<% provide(:title, @subject) %>
|
||||
|
||||
<p>
|
||||
Hello <%= @name %>,
|
||||
</p>
|
||||
|
||||
<% if @distribution.is_test_drive? %>
|
||||
<p>We have processed a payment to you via your Stripe account for $<%= @distribution.real_distribution_display %> for this lesson.</p>
|
||||
<% elsif @distribution.is_normal? %>
|
||||
<p>We have processed a payment to you via your Stripe account for $<%= @distribution.real_distribution_display %> for this lesson.</p>
|
||||
<% elsif @distribution.is_monthly? %>
|
||||
<p>We have processed a payment to you via your Stripe account for $<%= @distribution.real_distribution_display %> for <%= @distribution.month_name %> lessons.</p>
|
||||
<% else %>
|
||||
Unknown payment type.
|
||||
<% end %>
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
Best Regards,<br/>
|
||||
JamKazam
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<% provide(:title, @subject) %>
|
||||
|
||||
Hello <%= @name %>,
|
||||
|
||||
<% if @distribution.is_test_drive? %>
|
||||
We have processed a payment to you via your Stripe account for $<%= @distribution.real_distribution_display %> for this lesson.
|
||||
<% elsif @distribution.is_normal? %>
|
||||
We have processed a payment to you via your Stripe account for $<%= @distribution.real_distribution_display %> for this lesson.
|
||||
<% elsif @distribution.is_monthly? %>
|
||||
We have processed a payment to you via your Stripe account for $<%= @distribution.real_distribution_display %> for <%= @distribution.month_name %> lessons.
|
||||
<% else %>
|
||||
Unknown payment type.
|
||||
<% end %>
|
||||
|
||||
Best Regards,
|
||||
JamKazam
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
<% provide(:title, @subject) %>
|
||||
|
||||
|
||||
<% if !@user.anonymous? %>
|
||||
<p>Hello <%= EmailBatchProgression::VAR_FIRST_NAME %> --
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
<p>
|
||||
Thank you for expressing an interest in exploring our music school partner program! A member of our staff will reach out to you shortly to chat with you and answer any/all questions you may have about our partner program, our technologies, and how we can help you continue to build your music school business.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
We'd also like to provide links to some help articles that explain how many things work, and will likely answer many of your questions in a well-organized manner:
|
||||
</p>
|
||||
|
||||
|
||||
<p><a href="https://jamkazam.desk.com/customer/en/portal/topics/935633-jamclass-online-music-lessons---for-music-schools/articles" style="color:#fc0"><b style="color:#fc0">Guide for Music School Owners</b></a><br/>
|
||||
These help articles explain things from the perspective of the school owner - e.g. how you can schedule and book lessons from our marketplace with your teachers, how billing and payments are handled, and so on.
|
||||
</p>
|
||||
|
||||
<p><a href="https://jamkazam.desk.com/customer/en/portal/topics/926076-jamclass-online-music-lessons---for-teachers/articles" style="color:#fc0"><b style="color: #fc0">Guide for Music Lesson Teachers</b></a><br/>
|
||||
These help articles explain how teachers use the features of the platform outside of the online lesson sessions.
|
||||
</p>
|
||||
|
||||
<p><a href="https://jamkazam.desk.com/customer/en/portal/topics/673198-key-features-to-use-in-online-sessions/articles" style="color:#fc0"><b style="color: #fc0">Key Features To Use In Online Sessions</b></a><br/>
|
||||
These help articles explain the key features instructors can use in online sessions to teach effectively.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="https://jamkazam.desk.com/customer/en/portal/articles/1288274-computer-internet-audio-and-video-requirements"><b>Gear Requirements</b></a><br/>
|
||||
This help article explains the requirements for your computer, audio and video gear, and Internet service.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Thanks again for connecting with us, and we look forward to speaking with you soon!
|
||||
</p>
|
||||
<p>Best Regards,<br/>
|
||||
Team JamKazam</p>
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
<% if !@user.anonymous? %>
|
||||
Hello <%= EmailBatchProgression::VAR_FIRST_NAME %>
|
||||
<% end %>
|
||||
|
||||
Thank you for expressing an interest in exploring our music school partner program! A member of our staff will reach out to you shortly to chat with you and answer any/all questions you may have about our partner program, our technologies, and how we can help you continue to build your music school business.
|
||||
|
||||
We'd also like to provide links to some help articles that explain how many things work, and will likely answer many of your questions in a well-organized manner:
|
||||
|
||||
-- Guide for Music School Owners (https://jamkazam.desk.com/customer/en/portal/topics/935633-jamclass-online-music-lessons---for-music-schools/articles)
|
||||
These help articles explain things from the perspective of the school owner - e.g. how you can schedule and book lessons from our marketplace with your teachers, how billing and payments are handled, and so on.
|
||||
|
||||
-- Guide for Music Lesson Teachers (https://jamkazam.desk.com/customer/en/portal/topics/926076-jamclass-online-music-lessons---for-teachers/articles)
|
||||
These help articles explain how teachers use the features of the platform outside of the online lesson sessions.
|
||||
|
||||
-- Key Features To Use In Online Sessions (https://jamkazam.desk.com/customer/en/portal/topics/673198-key-features-to-use-in-online-sessions/articles)
|
||||
These help articles explain the key features instructors can use in online sessions to teach effectively.
|
||||
|
||||
-- Gear Requirements (https://jamkazam.desk.com/customer/en/portal/articles/1288274-computer-internet-audio-and-video-requirements)
|
||||
This help article explains the requirements for your computer, audio and video gear, and Internet service.
|
||||
|
||||
Thanks again for connecting with us, and we look forward to speaking with you soon!
|
||||
|
||||
Best Regards,
|
||||
Team JamKazam
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
<br/><%= @message %>
|
||||
<br/>
|
||||
<% end %>
|
||||
<br/><br/>Click the button below to get more information and to add this lesson to your calendar!
|
||||
<!--<br/><br/>Click the button below to get more information and to add this lesson to your calendar!-->
|
||||
<br/><br/>We strongly suggest adding this to your calendar so you don't forget it, or you'll end up paying for a lesson you don't get.</p>
|
||||
<p>
|
||||
<a href="<%= @lesson_session.web_url %>" style="margin: 8px 0 0 0;background-color: #ed3618;border: solid 1px #F27861;padding: 3px 10px;font-size: 12px;font-weight: 300;cursor: pointer;color: #FC9;text-decoration: none;line-height: 12px;text-align: center;">VIEW LESSON DETAILS</a>
|
||||
|
|
|
|||
|
|
@ -7,8 +7,7 @@
|
|||
</p>
|
||||
|
||||
<p>
|
||||
We hope you enjoyed your JamClass lesson today with <%= @teacher.name %>. You have been
|
||||
billed $<%= @lesson_session.amount_charged %> for today's lesson.
|
||||
We hope you enjoyed your JamClass lesson today with <%= @teacher.name %>. You have been billed $<%= @lesson_session.amount_charged %> for today's lesson.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
Hello <%= @student.name %>,
|
||||
</p>
|
||||
|
||||
<p>You will not be billed for today's session with <%= @teacher.name %>
|
||||
<p>You will not be billed for today's session with <%= @teacher.name %>.
|
||||
<br/>
|
||||
<br/>
|
||||
Click the button below to see more information about this session.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
Hello <%= @student.name %>,
|
||||
|
||||
You will not be billed for today's session with <%= @teacher.name %>
|
||||
You will not be billed for today's session with <%= @teacher.name %>.
|
||||
|
||||
To see this lesson, click here: <%= @lesson_session.web_url %>
|
||||
|
|
|
|||
|
|
@ -8,4 +8,4 @@
|
|||
<%= @session_date %>
|
||||
</p>
|
||||
|
||||
<p><a style="color: #ffcc00;" href="<%= @session_url %>">VIEW LESSON DETAILS</a></p>
|
||||
<p><a style="margin: 8px 0 0 0;background-color: #ed3618;border: solid 1px #F27861;padding: 3px 10px;font-size: 12px;font-weight: 300;cursor: pointer;color: #FC9;text-decoration: none;line-height: 12px;text-align: center;"href="<%= @session_url %>">VIEW LESSON DETAILS</a></p>
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
<% provide(:title, "You have used #{@student.remaining_test_drives} of 4 TestDrive lesson credits") %>
|
||||
<% provide(:title, "You have used #{@student.remaining_test_drives} of #{@student.total_test_drives} TestDrive lesson credits") %>
|
||||
<% provide(:photo_url, @teacher.resolved_photo_url) %>
|
||||
|
||||
<% content_for :note do %>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
You have used <%= @student.remaining_test_drives %> of 4 TestDrive lesson credits.
|
||||
You have used <%= @student.remaining_test_drives %> of <%= @student.total_test_drives %> TestDrive lesson credits.
|
||||
|
||||
<% if @student.has_rated_teacher(@teacher) %>
|
||||
Also, please rate your teacher at <%= @teacher.ratings_url %> now for today’s lesson to help other students in the community find the best instructors.
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
<% provide(:title, "You have used all 4 TestDrive lesson credits") %>
|
||||
<% provide(:title, "You have used all TestDrive lesson credits") %>
|
||||
|
||||
<p>
|
||||
Hello <%= @student.name %>,
|
||||
</p>
|
||||
|
||||
<p>
|
||||
We hope you enjoyed your JamClass lesson today with <%= @teacher.name %>. You have now used all 4 TestDrive credits.
|
||||
We hope you enjoyed your JamClass lesson today with <%= @teacher.name %>. You have now used all your TestDrive credits.
|
||||
|
||||
<% if !@student.has_rated_teacher(@teacher) %>
|
||||
Please <a href="<%= @teacher.ratings_url %>" style="color:#fc0">rate your teacher</a> now for today’s lesson to
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
You have used all of your 4 TestDrive lesson credits.
|
||||
You have used all of your TestDrive lesson credits.
|
||||
|
||||
<% if @student.has_rated_teacher(@teacher) %>
|
||||
Also, please rate your teacher at <%= @teacher.ratings_url %> now for today’s lesson to help other students in the community find the best instructors.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
<% provide(:title, "Your TestDrive with #{@teacher.name} will not be billed") %>
|
||||
<% provide(:photo_url, @teacher.resolved_photo_url) %>
|
||||
|
||||
<% content_for :note do %>
|
||||
<p>
|
||||
Hello <%= @student.name %>,
|
||||
</p>
|
||||
|
||||
<p>You have not used a credit for today's TestDrive with <%= @teacher.name %>.
|
||||
<br/>
|
||||
<br/>
|
||||
Click the button below to see more information about this session.
|
||||
</p>
|
||||
<p>
|
||||
<a href="<%= @lesson_session.web_url %>" style="margin: 8px 0 0 0;background-color: #ed3618;border: solid 1px #F27861;padding: 3px 10px;font-size: 12px;font-weight: 300;cursor: pointer;color: #FC9;text-decoration: none;line-height: 12px;text-align: center;">VIEW
|
||||
LESSON DETAILS</a>
|
||||
</p>
|
||||
<p>
|
||||
Best Regards,<br>Team JamKazam
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
Hello <%= @student.name %>,
|
||||
|
||||
You have not used a credit for today's TestDrive with <%= @teacher.name %>.
|
||||
|
||||
To see this lesson, click here: <%= @lesson_session.web_url %>
|
||||
|
|
@ -32,7 +32,7 @@
|
|||
teacher for you. Finding the right teacher is the single most important determinant of success in your lessons. Would
|
||||
you marry the first person you ever dated? No? Same here. Pick 4 teachers who look great, and then see who you click
|
||||
with. It's a phenomenal value, and then you can stick with the best teacher for you.
|
||||
<a href="https://www.jamkazam.com/client#/jamclass/book-lesson/purchase_test-drive" style="color:#fc0">Click this link
|
||||
<a href="https://www.jamkazam.com/client#/jamclass/lesson-payment/test-drive" style="color:#fc0">Click this link
|
||||
to sign up now
|
||||
for TestDrive</a>. Then you can book 4 TestDrive lessons to get rolling.
|
||||
</p>
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ TestDrive lets you take 4 full lessons (30 minutes each) from 4 different teache
|
|||
teacher for you. Finding the right teacher is the single most important determinant of success in your lessons. Would
|
||||
you marry the first person you ever dated? No? Same here. Pick 4 teachers who look great, and then see who you click
|
||||
with. It's a phenomenal value, and then you can stick with the best teacher for you.
|
||||
Click this link to sign up now for TestDrive (https://www.jamkazam.com/client#/jamclass/book-lesson/purchase_test-drive).
|
||||
Click this link to sign up now for TestDrive (https://www.jamkazam.com/client#/jamclass/test-drive-selection).
|
||||
Then you can book 4 TestDrive lessons to get rolling.
|
||||
|
||||
2. Set Up Your Gear
|
||||
|
|
|
|||
|
|
@ -1,31 +1,42 @@
|
|||
<% provide(:title, @subject) %>
|
||||
|
||||
<p>You were paid a total of $<%= @teacher_payment.amount %> for your participation in JamClass. Below are more details:</p>
|
||||
<br/>
|
||||
<p>
|
||||
Hello <%= @name %>,
|
||||
</p>
|
||||
|
||||
<% @teacher_payment.teacher_distributions.each do |distribution| %>
|
||||
|
||||
<% if distribution.is_test_drive? %>
|
||||
<h3>You have earned $<%= distribution.amount %> for your TestDrive lesson with <%= distribution.student.name %></h3>
|
||||
<% if @distribution.is_test_drive? %>
|
||||
<% if @school %>
|
||||
<h3>We hope you enjoyed your TestDrive lesson today with <%= @distribution.student.name %>.</h3>
|
||||
<% else %>
|
||||
<h3>You have earned $<%= @distribution.real_distribution_display %> for your TestDrive lesson with <%= @distribution.student.name %>.</h3>
|
||||
<% end %>
|
||||
<p>
|
||||
<% if !@teacher_payment.teacher.has_rated_student(distribution.student) %>
|
||||
If you haven't already done so, please <a href="<%= distribution.student.student_ratings_url %>" style="color:#fc0">rate your student</a> now to help us monitor for any issues with students who may cause issues for our instructor community.
|
||||
<% if !@teacher_payment.teacher.has_rated_student(@distribution.student) %>
|
||||
If you haven't already done so, please <a href="<%= @distribution.student.student_ratings_url %>" style="color:#fc0">rate your student</a> now to help us monitor for any issues with students who may cause issues for our instructor community.
|
||||
<% end %>
|
||||
If you had technical problems during your lesson, or have questions, or would like to make suggestions on how to improve JamClass, please email us at <a href="mailto:support@jamkazam.com" style="color:#fc0">support@jamkazam.com</a>.
|
||||
</p>
|
||||
<% elsif distribution.is_normal? %>
|
||||
<h3>You have earned $<%= distribution.amount %> for your lesson with <%= distribution.student.name %></h3>
|
||||
<% elsif @distribution.is_normal? %>
|
||||
<% if @school %>
|
||||
<h3>we hope you enjoyed your lesson today with <%= @distribution.student.name %>.</h3>
|
||||
<% else %>
|
||||
<h3>You have earned $<%= @distribution.real_distribution_display %> for your lesson with <%= @distribution.student.name %>.</h3>
|
||||
<% end %>
|
||||
<p>
|
||||
<% if !@teacher_payment.teacher.has_rated_student(distribution.student) %>
|
||||
If you haven't already done so, please <a href="<%= distribution.student.student_ratings_url %>" style="color:#fc0">rate your student</a> now to help us monitor for any issues with students who may cause issues for our instructor community.
|
||||
<% if !@teacher_payment.teacher.has_rated_student(@distribution.student) %>
|
||||
If you haven't already done so, please <a href="<%= @distribution.student.student_ratings_url %>" style="color:#fc0">rate your student</a> now to help us monitor for any issues with students who may cause issues for our instructor community.
|
||||
<% end %>
|
||||
If you had technical problems during your lesson, or have questions, or would like to make suggestions on how to improve JamClass, please email us at <a href="mailto:support@jamkazam.com" style="color:#fc0">support@jamkazam.com</a>.
|
||||
</p>
|
||||
<% elsif distribution.is_monthly? %>
|
||||
<h3>You have earned $<%= distribution.amount %> for your <%= distribution.month_name%> lesson with <%= distribution.student.name %></h3>
|
||||
<% elsif @distribution.is_monthly? %>
|
||||
<% if @school %>
|
||||
<h3>we hope you enjoyed your <%= @distribution.month_name %> lessons with <%= @distribution.student.name %>.</h3>
|
||||
<% else %>
|
||||
<h3>You have earned $<%= @distribution.real_distribution_display %> for your <%= @distribution.month_name%> lessons with <%= @distribution.student.name %>.</h3>
|
||||
<% end %>
|
||||
<p>
|
||||
<% if !@teacher_payment.teacher.has_rated_student(distribution.student) %>
|
||||
If you haven't already done so, please <a href="<%= distribution.student.student_ratings_url %>" style="color:#fc0">rate your student</a> now to help us monitor for any issues with students who may cause issues for our instructor community.
|
||||
<% if !@teacher_payment.teacher.has_rated_student(@distribution.student) %>
|
||||
If you haven't already done so, please <a href="<%= @distribution.student.student_ratings_url %>" style="color:#fc0">rate your student</a> now to help us monitor for any issues with students who may cause issues for our instructor community.
|
||||
<% end %>
|
||||
If you had technical problems during your lesson, or have questions, or would like to make suggestions on how to improve JamClass, please email us at <a href="mailto:support@jamkazam.com" style="color:#fc0">support@jamkazam.com</a>.
|
||||
</p>
|
||||
|
|
@ -35,7 +46,5 @@
|
|||
<br/>
|
||||
<br/>
|
||||
|
||||
<% end %>
|
||||
|
||||
Best Regards,<br/>
|
||||
JamKazam
|
||||
|
|
@ -1,31 +1,40 @@
|
|||
<% provide(:title, @subject) %>
|
||||
|
||||
You were paid a total of $<%= @teacher_payment.amount %> for your participation in JamClass. Below are more details:
|
||||
Hello <%= @name %>,
|
||||
|
||||
<% @teacher_payment.teacher_distributions.each do |distribution| %>
|
||||
|
||||
<% if distribution.is_test_drive? %>
|
||||
You have earned $<%= distribution.amount %> for your TestDrive lesson with <%= distribution.student.name %>.
|
||||
<% if !@teacher_payment.teacher.has_rated_student(distribution.student) %>
|
||||
If you haven't already done so, please rate your student now to help us monitor for any issues with students who may cause issues for our instructor community. <%= distribution.student.student_ratings_url %>
|
||||
<% if @distribution.is_test_drive? %>
|
||||
<% if @school %>
|
||||
We hope you enjoyed your TestDrive lesson today with <%= @distribution.student.name %>.
|
||||
<% else %>
|
||||
You have earned $<%= @distribution.amount %> for your TestDrive lesson with <%= @distribution.student.name %>.
|
||||
<% end %>
|
||||
<% if !@teacher_payment.teacher.has_rated_student(@distribution.student) %>
|
||||
If you haven't already done so, please rate your student now to help us monitor for any issues with students who may cause issues for our instructor community. <%= @distribution.student.student_ratings_url %>
|
||||
<% end%>
|
||||
If you had technical problems during your lesson, or have questions, or would like to make suggestions on how to improve JamClass, please email us at support@jamkazam.com.
|
||||
<% elsif distribution.is_normal? %>
|
||||
You have earned $<%= distribution.amount %> for your lesson with <%= distribution.student.name %>.
|
||||
<% if !@teacher_payment.teacher.has_rated_student(distribution.student) %>
|
||||
If you haven't already done so, please rate your student now to help us monitor for any issues with students who may cause issues for our instructor community. <%= distribution.student.student_ratings_url %>
|
||||
<% elsif @distribution.is_normal? %>
|
||||
<% if @school %>
|
||||
We hope you enjoyed your lesson today with <%= @distribution.student.name %>.
|
||||
<% else %>
|
||||
You have earned $<%= @distribution.amount %> for your lesson with <%= @distribution.student.name %>.
|
||||
<% end %>
|
||||
<% if !@teacher_payment.teacher.has_rated_student(@distribution.student) %>
|
||||
If you haven't already done so, please rate your student now to help us monitor for any issues with students who may cause issues for our instructor community. <%= @distribution.student.student_ratings_url %>
|
||||
<% end%>
|
||||
If you had technical problems during your lesson, or have questions, or would like to make suggestions on how to improve JamClass, please email us at support@jamkazam.com.
|
||||
<% elsif distribution.is_monthly? %>
|
||||
You have earned $<%= distribution.amount %> for your <%= distribution.month_name%> lesson with <%= distribution.student.name %>.
|
||||
<% if !@teacher_payment.teacher.has_rated_student(distribution.student) %>
|
||||
If you haven't already done so, please rate your student now to help us monitor for any issues with students who may cause issues for our instructor community. <%= distribution.student.student_ratings_url %>
|
||||
<% elsif @distribution.is_monthly? %>
|
||||
<% if @school %>
|
||||
We hope you enjoyed your <%= @distribution.month_name%> lessons with <%= @distribution.student.name %>.
|
||||
<% else %>
|
||||
You have earned $<%= @distribution.amount %> for your <%= @distribution.month_name%> lessons with <%= @distribution.student.name %>.
|
||||
<% end %>
|
||||
<% if !@teacher_payment.teacher.has_rated_student(@distribution.student) %>
|
||||
If you haven't already done so, please rate your student now to help us monitor for any issues with students who may cause issues for our instructor community. <%= @distribution.student.student_ratings_url %>
|
||||
<% end%>
|
||||
If you had technical problems during your lesson, or have questions, or would like to make suggestions on how to improve JamClass, please email us at support@jamkazam.com.
|
||||
<% else %>
|
||||
Unknown payment type.
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
Best Regards,
|
||||
JamKazam
|
||||
|
|
@ -1,5 +1,12 @@
|
|||
<% provide(:title, @subject) %>
|
||||
|
||||
<p>Hello <%= @name %>,</p>
|
||||
|
||||
<% if @school %>
|
||||
<p>
|
||||
We attempted to process a payment via your Stripe account for <%= @distribution.real_distribution_display %> for this lesson, but the payment failed. Please sign into your Stripe account, and verify that everything there is working properly. We’ll try again to process this payment in about 24 hours.
|
||||
</p>
|
||||
<% else %>
|
||||
<p>
|
||||
<% if @card_declined %>
|
||||
When we tried to distribute a payment to you on <%= @bill_date %>, the charge was declined by stripe. Can you please check your stripe account status? Thank you!
|
||||
|
|
@ -9,6 +16,7 @@
|
|||
For some reason, when we tried to distribute a payment to you on <%= @bill_date %>, the charge failed. Can you please check your stripe account status? Thank you!
|
||||
<% end %>
|
||||
</p>
|
||||
<% end %>
|
||||
<br/>
|
||||
|
||||
Best Regards,<br/>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
<% provide(:title, @subject) %>
|
||||
Hello <%= @name %>,
|
||||
|
||||
<% if @school %>
|
||||
We attempted to process a payment via your Stripe account for <%= @distribution.real_distribution_display %> for this lesson, but the payment failed. Please sign into your Stripe account, and verify that everything there is working properly. We’ll try again to process this payment in about 24 hours.
|
||||
<% else %>
|
||||
<% if @card_declined %>
|
||||
When we tried to distribute a payment to you on <%= @bill_date %>, the charge was declined by stripe. Can you please check your stripe account status? Thank you!
|
||||
<% elsif @card_expired %>
|
||||
|
|
@ -7,6 +11,7 @@ When we tried to distribute a payment to you on <%= @bill_date %>, the charge wa
|
|||
<% else %>
|
||||
For some reason, when we tried to distribute a payment to you on <%= @bill_date %>, the charge failed. Can you please check your stripe account status? Thank you!
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
Best Regards,
|
||||
JamKazam
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
<% else %>
|
||||
This student has accepted your lesson request!
|
||||
<% end %>
|
||||
<br/><br/>Click the button below to get more information and to add this lesson to your calendar!
|
||||
<!--<br/><br/>Click the button below to get more information and to add this lesson to your calendar!-->
|
||||
<br/><br/>We strongly suggest adding this to your calendar so you don't forget it.</p>
|
||||
<p>
|
||||
<a href="<%= @lesson_session.web_url %>" style="margin: 8px 0 0 0;background-color: #ed3618;border: solid 1px #F27861;padding: 3px 10px;font-size: 12px;font-weight: 300;cursor: pointer;color: #FC9;text-decoration: none;line-height: 12px;text-align: center;">VIEW LESSON DETAILS</a>
|
||||
|
|
|
|||
|
|
@ -8,4 +8,4 @@
|
|||
<%= @session_date %>
|
||||
</p>
|
||||
|
||||
<p><a style="color: #ffcc00;" href="<%= @session_url %>">VIEW LESSON DETAILS</a></p>
|
||||
<p><a style="margin: 8px 0 0 0;background-color: #ed3618;border: solid 1px #F27861;padding: 3px 10px;font-size: 12px;font-weight: 300;cursor: pointer;color: #FC9;text-decoration: none;line-height: 12px;text-align: center;"href="<%= @session_url %>">VIEW LESSON DETAILS</a></p>
|
||||
|
|
@ -419,7 +419,7 @@ SQL
|
|||
end
|
||||
|
||||
connection.join_the_session(music_session, as_musician, tracks, user, audio_latency, video_sources)
|
||||
JamRuby::MusicSessionUserHistory.join_music_session(user.id, music_session.id)
|
||||
JamRuby::MusicSessionUserHistory.join_music_session(user.id, music_session.id, client_id)
|
||||
# connection.music_session_id = music_session.id
|
||||
# connection.as_musician = as_musician
|
||||
# connection.joining_session = true
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
require 'influxdb'
|
||||
#require 'influxdb'
|
||||
|
||||
# monkey patch InfluxDB client to clear the queue when asked to stop
|
||||
=begin
|
||||
|
|
|
|||
|
|
@ -993,14 +993,16 @@ module JamRuby
|
|||
end
|
||||
|
||||
# creates the chat message
|
||||
def chat_message(session_id, sender_name, sender_id, msg, msg_id, created_at, channel)
|
||||
def chat_message(session_id, sender_name, sender_id, msg, msg_id, created_at, channel, lesson_session_id, purpose)
|
||||
chat_message = Jampb::ChatMessage.new(
|
||||
:sender_id => sender_id,
|
||||
:sender_name => sender_name,
|
||||
:msg => msg,
|
||||
:msg_id => msg_id,
|
||||
:created_at => created_at,
|
||||
:channel => channel
|
||||
:channel => channel,
|
||||
:lesson_session_id => lesson_session_id,
|
||||
:purpose => purpose
|
||||
)
|
||||
|
||||
if session_id
|
||||
|
|
|
|||
|
|
@ -843,5 +843,9 @@ module JamRuby
|
|||
|
||||
stats
|
||||
end
|
||||
|
||||
def lesson_session
|
||||
music_session.lesson_session
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -357,7 +357,7 @@ class JamRuby::AffiliatePartner < ActiveRecord::Base
|
|||
UPDATE affiliate_quarterly_payments
|
||||
SET
|
||||
closed = TRUE, closed_at = NOW()
|
||||
WHERE year < #{year} OR quarter < #{quarter}
|
||||
WHERE year < #{year} OR (year = #{year} AND quarter < #{quarter})
|
||||
}
|
||||
|
||||
ActiveRecord::Base.connection.execute(sql)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
module JamRuby
|
||||
class AffiliatePaymentCharge < Charge
|
||||
|
||||
has_one :teacher_payment, class_name: "JamRuby::TeacherPayment", foreign_key: :affiliate_charge_id
|
||||
#has_one :teacher_payment, class_name: "JamRuby::TeacherPayment", foreign_key: :affiliate_charge_id
|
||||
|
||||
def distribution
|
||||
@distribution ||= teacher_payment.teacher_distribution
|
||||
|
|
@ -36,15 +36,15 @@ module JamRuby
|
|||
end
|
||||
|
||||
def do_send_notices
|
||||
UserMailer.teacher_distribution_done(teacher_payment)
|
||||
#UserMailer.teacher_distribution_done(teacher_payment)
|
||||
end
|
||||
|
||||
def do_send_unable_charge
|
||||
UserMailer.teacher_distribution_fail(teacher_payment)
|
||||
#UserMailer.teacher_distribution_fail(teacher_payment)
|
||||
end
|
||||
|
||||
def construct_description
|
||||
teacher_payment.teacher_distribution.description
|
||||
#teacher_payment.teacher_distribution.description
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ module JamRuby
|
|||
DEFAULT_ENVIRONMENT = 'public'
|
||||
CLIENT_PREFIX = 'JamClient'
|
||||
|
||||
PRODUCTS = ["#{CLIENT_PREFIX}/Win32", "#{CLIENT_PREFIX}/MacOSX"]
|
||||
PRODUCTS = ["#{CLIENT_PREFIX}/Win32", "#{CLIENT_PREFIX}/MacOSX", "#{CLIENT_PREFIX}/JamBlaster"]
|
||||
|
||||
self.primary_key = 'id'
|
||||
attr_accessible :version, :uri, :sha1, :environment, :product, as: :admin
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
module JamRuby
|
||||
class Charge < ActiveRecord::Base
|
||||
|
||||
belongs_to :user, class_name: "JamRuby::User"
|
||||
|
||||
validates :sent_billing_notices, inclusion: {in: [true, false]}
|
||||
|
||||
def max_retries
|
||||
|
|
@ -96,6 +98,7 @@ module JamRuby
|
|||
else
|
||||
self.billing_error_detail = e.to_s + "\n" + e.backtrace.join("\n\t") if e.backtrace
|
||||
end
|
||||
puts "Charge: unhandled exception #{billing_error_reason}, #{billing_error_detail}"
|
||||
self.save(validate: false)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -16,26 +16,44 @@ module JamRuby
|
|||
belongs_to :user
|
||||
belongs_to :music_session
|
||||
belongs_to :target_user, class_name: "JamRuby::User"
|
||||
belongs_to :lesson_booking, class_name: "JamRuby::LessonBooking"
|
||||
belongs_to :lesson_session, class_name: "JamRuby::LessonSession"
|
||||
|
||||
validates :user, presence: true
|
||||
validates :message, length: {minimum: 1, maximum: 255}, no_profanity: true, unless: :ignore_message_checks
|
||||
|
||||
def self.create(user, music_session, message, channel, client_id, target_user = nil, lesson_booking = nil)
|
||||
def self.create(user, music_session, message, channel, client_id, target_user = nil, lesson_session = nil, purpose = nil)
|
||||
chat_msg = ChatMessage.new
|
||||
chat_msg.user_id = user.id
|
||||
chat_msg.music_session_id = music_session.id if music_session
|
||||
chat_msg.message = message
|
||||
chat_msg.channel = channel
|
||||
chat_msg.target_user = target_user
|
||||
chat_msg.lesson_booking = lesson_booking
|
||||
chat_msg.lesson_session = lesson_session
|
||||
chat_msg.purpose = purpose
|
||||
|
||||
if lesson_booking
|
||||
|
||||
if lesson_session
|
||||
chat_msg.ignore_message_checks = true
|
||||
|
||||
if user.id == lesson_session.student.id
|
||||
lesson_session.teacher_unread_messages = true
|
||||
Notification.send_lesson_message('chat', lesson_session, false, message)
|
||||
else
|
||||
lesson_session.student_unread_messages = true
|
||||
Notification.send_lesson_message('chat', lesson_session, true, message)
|
||||
end
|
||||
|
||||
lesson_session.save(validate: false)
|
||||
|
||||
# a nil purpose means 'normal chat', which is the only time we should send an email
|
||||
if !target_user.online? && purpose.nil? && message.present?
|
||||
UserMailer.lesson_chat(chat_msg).deliver!
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
if chat_msg.save
|
||||
ChatMessage.send_chat_msg music_session, chat_msg, user, client_id, channel
|
||||
ChatMessage.send_chat_msg music_session, chat_msg, user, client_id, channel, lesson_session, purpose, target_user
|
||||
end
|
||||
chat_msg
|
||||
end
|
||||
|
|
@ -60,6 +78,11 @@ module JamRuby
|
|||
query = ChatMessage.where('music_session_id = ?', music_session_id)
|
||||
end
|
||||
|
||||
if params.has_key? (:lesson_session)
|
||||
lesson_session_id = params[:lesson_session]
|
||||
query = ChatMessage.where('lesson_session_id = ?', lesson_session_id)
|
||||
end
|
||||
|
||||
query = query.offset(start).limit(limit).order('created_at DESC').includes([:user])
|
||||
|
||||
if query.length == 0
|
||||
|
|
@ -71,8 +94,9 @@ module JamRuby
|
|||
end
|
||||
end
|
||||
|
||||
def send_chat_msg(music_session, chat_msg, user, client_id, channel)
|
||||
def send_chat_msg(music_session, chat_msg, user, client_id, channel, lesson_session, purpose, target_user)
|
||||
music_session_id = music_session.id if music_session
|
||||
lesson_session_id = lesson_session.id if lesson_session
|
||||
|
||||
msg = @@message_factory.chat_message(
|
||||
music_session_id,
|
||||
|
|
@ -81,14 +105,19 @@ module JamRuby
|
|||
chat_msg.message,
|
||||
chat_msg.id,
|
||||
chat_msg.created_at.utc.iso8601,
|
||||
channel
|
||||
channel,
|
||||
lesson_session_id,
|
||||
purpose
|
||||
)
|
||||
|
||||
if channel == 'session'
|
||||
@@mq_router.server_publish_to_session(music_session, msg, sender = {:client_id => client_id})
|
||||
elsif channel == 'global'
|
||||
@@mq_router.publish_to_active_clients(msg)
|
||||
elsif channel == 'lesson'
|
||||
@@mq_router.publish_to_user(target_user.id, msg, sender = {:client_id => client_id})
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ module JamRuby
|
|||
has_and_belongs_to_many :teachers, :class_name => "JamRuby::Teacher", :join_table => "teachers_instruments"
|
||||
|
||||
def self.standard_list
|
||||
return Instrument.where('instruments.popularity > 0').order('instruments.popularity DESC, instruments.description ASC')
|
||||
return Instrument.where('instruments.popularity > 0').order('instruments.description ASC')
|
||||
end
|
||||
|
||||
def self.jam_track_list
|
||||
|
|
|
|||
|
|
@ -3,5 +3,10 @@ module JamRuby
|
|||
include HtmlSanitize
|
||||
html_sanitize strict: [:name, :description]
|
||||
has_and_belongs_to_many :teachers, :class_name => "JamRuby::Teacher", :join_table => "teachers_languages"
|
||||
|
||||
def self.english_sort
|
||||
languages = Language.order(:description)
|
||||
languages.sort_by { |l| [ l.id == 'EN' ? 0 : 1, l.description] }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ module JamRuby
|
|||
|
||||
@@log = Logging.logger[LessonBooking]
|
||||
|
||||
attr_accessor :accepting, :countering, :countered_slot, :countered_lesson
|
||||
attr_accessor :accepting, :countering, :canceling, :countered_slot, :countered_lesson
|
||||
|
||||
STATUS_REQUESTED = 'requested'
|
||||
STATUS_CANCELED = 'canceled'
|
||||
|
|
@ -37,12 +37,12 @@ module JamRuby
|
|||
belongs_to :teacher, class_name: "JamRuby::User"
|
||||
belongs_to :accepter, class_name: "JamRuby::User"
|
||||
belongs_to :canceler, class_name: "JamRuby::User"
|
||||
belongs_to :default_slot, class_name: "JamRuby::LessonBookingSlot", foreign_key: :default_slot_id, inverse_of: :defaulted_booking
|
||||
belongs_to :counter_slot, class_name: "JamRuby::LessonBookingSlot", foreign_key: :counter_slot_id, inverse_of: :countered_booking
|
||||
|
||||
has_many :lesson_booking_slots, class_name: "JamRuby::LessonBookingSlot"
|
||||
has_many :lesson_sessions, class_name: "JamRuby::LessonSession"
|
||||
has_many :lesson_package_purchases, class_name: "JamRuby::LessonPackagePurchase"
|
||||
belongs_to :default_slot, class_name: "JamRuby::LessonBookingSlot", foreign_key: :default_slot_id, inverse_of: :defaulted_booking, :dependent => :destroy
|
||||
belongs_to :counter_slot, class_name: "JamRuby::LessonBookingSlot", foreign_key: :counter_slot_id, inverse_of: :countered_booking, :dependent => :destroy
|
||||
belongs_to :school, class_name: "JamRuby::School"
|
||||
has_many :lesson_booking_slots, class_name: "JamRuby::LessonBookingSlot", :dependent => :destroy
|
||||
has_many :lesson_sessions, class_name: "JamRuby::LessonSession", :dependent => :destroy
|
||||
has_many :lesson_package_purchases, class_name: "JamRuby::LessonPackagePurchase", :dependent => :destroy
|
||||
|
||||
validates :user, presence: true
|
||||
validates :teacher, presence: true
|
||||
|
|
@ -62,7 +62,9 @@ module JamRuby
|
|||
validate :validate_lesson_booking_slots
|
||||
validate :validate_lesson_length
|
||||
validate :validate_payment_style
|
||||
validate :validate_uncollectables, on: :create
|
||||
validate :validate_accepted, :if => :accepting
|
||||
validate :validate_canceled, :if => :canceling
|
||||
|
||||
|
||||
before_save :before_save
|
||||
|
|
@ -85,7 +87,7 @@ module JamRuby
|
|||
end
|
||||
|
||||
def after_create
|
||||
if card_presumed_ok && !sent_notices
|
||||
if (card_presumed_ok || school_on_school?) && !sent_notices
|
||||
send_notices
|
||||
end
|
||||
end
|
||||
|
|
@ -136,6 +138,9 @@ module JamRuby
|
|||
def next_lesson
|
||||
if recurring
|
||||
session = lesson_sessions.joins(:music_session).where("scheduled_start is not null").where("scheduled_start > ?", Time.now).order(:created_at).first
|
||||
if session.nil?
|
||||
session = lesson_sessions[0]
|
||||
end
|
||||
LessonSession.find(session.id) if session
|
||||
else
|
||||
lesson_sessions[0]
|
||||
|
|
@ -272,7 +277,7 @@ module JamRuby
|
|||
times << time
|
||||
end
|
||||
end
|
||||
times
|
||||
{ times: times, session: sessions.first }
|
||||
end
|
||||
|
||||
def determine_needed_sessions(sessions)
|
||||
|
|
@ -390,6 +395,14 @@ module JamRuby
|
|||
self.accepting = false
|
||||
end
|
||||
|
||||
def validate_canceled
|
||||
if !is_canceled?
|
||||
self.errors.add(:status, "This session is already #{self.status}.")
|
||||
end
|
||||
|
||||
self.canceling = false
|
||||
end
|
||||
|
||||
def send_notices
|
||||
UserMailer.student_lesson_request(self).deliver
|
||||
UserMailer.teacher_lesson_request(self).deliver
|
||||
|
|
@ -398,11 +411,26 @@ module JamRuby
|
|||
self.save
|
||||
end
|
||||
|
||||
def resolved_test_drive_package
|
||||
result = nil
|
||||
purchase = student.most_recent_test_drive_purchase
|
||||
if purchase
|
||||
# for lessons already packaged
|
||||
result = purchase.lesson_package_type
|
||||
else
|
||||
# for unbooked lessons
|
||||
result = student.desired_package
|
||||
end
|
||||
if result.nil?
|
||||
result = LessonPackageType.test_drive_4
|
||||
end
|
||||
result
|
||||
end
|
||||
def lesson_package_type
|
||||
if is_single_free?
|
||||
LessonPackageType.single_free
|
||||
elsif is_test_drive?
|
||||
LessonPackageType.test_drive
|
||||
resolved_test_drive_package
|
||||
elsif is_normal?
|
||||
LessonPackageType.single
|
||||
end
|
||||
|
|
@ -439,19 +467,32 @@ module JamRuby
|
|||
if is_single_free?
|
||||
0
|
||||
elsif is_test_drive?
|
||||
LessonPackageType.test_drive.price
|
||||
resolved_test_drive_package.price
|
||||
elsif is_normal?
|
||||
teacher.teacher.booking_price(lesson_length, payment_style != PAYMENT_STYLE_MONTHLY)
|
||||
end
|
||||
end
|
||||
|
||||
def distribution_price_in_cents
|
||||
def distribution_price_in_cents(target)
|
||||
if is_single_free?
|
||||
0
|
||||
elsif is_test_drive?
|
||||
10 * 100
|
||||
elsif is_normal?
|
||||
booked_price * 100
|
||||
if is_monthly_payment?
|
||||
raise "not a LessonPackagePurchase: #{target.inspect}" if !target.is_a?(LessonPackagePurchase)
|
||||
|
||||
today = Date.today
|
||||
|
||||
start_date = Date.new(target.year, target.month, 1)
|
||||
if today.year == target.year && today.month == target.month
|
||||
# we are in the month being billed. we should set the start date based on today
|
||||
start_date = today
|
||||
end
|
||||
LessonSessionMonthlyPrice.price(self, start_date) * 100
|
||||
else
|
||||
booked_price * 100
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -500,41 +541,49 @@ module JamRuby
|
|||
def approved_before?
|
||||
!self.accepter_id.nil?
|
||||
end
|
||||
|
||||
def cancel(canceler, other, message)
|
||||
|
||||
self.canceling = true
|
||||
self.active = false
|
||||
self.status = STATUS_CANCELED
|
||||
self.cancel_message = message
|
||||
self.canceler = canceler
|
||||
success = save
|
||||
if success
|
||||
lesson_sessions.past_cancel_window.each do |lesson_session|
|
||||
lesson_session = LessonSession.find(lesson_session.id) # because .upcoming creates ReadOnly records
|
||||
lesson_session.cancel_lesson(canceler, message)
|
||||
if !lesson_session.save
|
||||
return lesson_session
|
||||
end
|
||||
end
|
||||
if approved_before?
|
||||
# just tell both people it's cancelled, to act as confirmation
|
||||
Notification.send_lesson_message('canceled', next_lesson, false)
|
||||
Notification.send_lesson_message('canceled', next_lesson, true)
|
||||
UserMailer.student_lesson_booking_canceled(self, message).deliver
|
||||
UserMailer.teacher_lesson_booking_canceled(self, message).deliver
|
||||
chat_message_prefix = "Lesson Canceled"
|
||||
purpose = "Lesson Canceled"
|
||||
else
|
||||
if canceler == student
|
||||
# if it's the first time acceptance student canceling, we call it a 'cancel'
|
||||
Notification.send_lesson_message('canceled', next_lesson, false)
|
||||
UserMailer.teacher_lesson_booking_canceled(self, message).deliver
|
||||
chat_message_prefix = "Lesson Canceled"
|
||||
purpose = "Lesson Canceled"
|
||||
else
|
||||
# if it's the first time acceptance teacher, it was declined
|
||||
UserMailer.student_lesson_booking_declined(self, message).deliver
|
||||
Notification.send_lesson_message('declined', next_lesson, true)
|
||||
chat_message_prefix = "Lesson Declined"
|
||||
purpose = "Lesson Declined"
|
||||
end
|
||||
end
|
||||
|
||||
chat_message = message.nil? ? chat_message_prefix : "#{chat_message_prefix}: #{message}"
|
||||
msg = ChatMessage.create(canceler, nil, chat_message, ChatMessage::CHANNEL_LESSON, nil, other, self)
|
||||
|
||||
message = '' if message.nil?
|
||||
msg = ChatMessage.create(canceler, nil, message, ChatMessage::CHANNEL_LESSON, nil, other, next_lesson, purpose)
|
||||
end
|
||||
|
||||
success
|
||||
self
|
||||
end
|
||||
|
||||
def card_approved
|
||||
|
|
@ -555,7 +604,7 @@ module JamRuby
|
|||
#end
|
||||
elsif is_test_drive?
|
||||
if user.has_requested_test_drive?(teacher) && !user.admin
|
||||
errors.add(:user, "has a requested TestDrive with this teacher")
|
||||
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")
|
||||
|
|
@ -603,6 +652,15 @@ module JamRuby
|
|||
end
|
||||
end
|
||||
|
||||
def validate_uncollectables
|
||||
if user.uncollectables.count > 0
|
||||
errors.add(:user, 'have unpaid lessons.')
|
||||
end
|
||||
end
|
||||
|
||||
def school_owned?
|
||||
!!school
|
||||
end
|
||||
|
||||
def self.book_free(user, teacher, lesson_booking_slots, description)
|
||||
self.book(user, teacher, LessonBooking::LESSON_TYPE_FREE, lesson_booking_slots, false, 30, PAYMENT_STYLE_ELSEWHERE, description)
|
||||
|
|
@ -632,6 +690,9 @@ module JamRuby
|
|||
lesson_booking.payment_style = payment_style
|
||||
lesson_booking.description = description
|
||||
lesson_booking.status = STATUS_REQUESTED
|
||||
if lesson_booking.teacher && lesson_booking.teacher.teacher.school
|
||||
lesson_booking.school = lesson_booking.teacher.teacher.school
|
||||
end
|
||||
|
||||
# two-way association slots, for before_validation loic in slot to work
|
||||
lesson_booking.lesson_booking_slots = lesson_booking_slots
|
||||
|
|
@ -641,20 +702,24 @@ module JamRuby
|
|||
end if lesson_booking_slots
|
||||
|
||||
if lesson_booking.save
|
||||
msg = ChatMessage.create(user, lesson_booking.lesson_sessions[0], description, ChatMessage::CHANNEL_LESSON, nil, teacher, lesson_booking)
|
||||
description = '' if description.nil?
|
||||
msg = ChatMessage.create(user, lesson_booking.lesson_sessions[0], description, ChatMessage::CHANNEL_LESSON, nil, teacher, lesson_booking.lesson_sessions[0], 'Lesson Requested')
|
||||
end
|
||||
end
|
||||
lesson_booking
|
||||
end
|
||||
|
||||
def self.unprocessed(current_user)
|
||||
LessonBooking.where(user_id: current_user.id).where(card_presumed_ok: false)
|
||||
LessonBooking.where(user_id: current_user.id).where(card_presumed_ok: false).where('school_id IS NULL')
|
||||
end
|
||||
|
||||
def self.requested(current_user)
|
||||
LessonBooking.where(user_id: current_user.id).where(status: STATUS_REQUESTED)
|
||||
end
|
||||
|
||||
def school_on_school?
|
||||
teacher.teacher.school && student.school && (teacher.teacher.school.id == student.school.id)
|
||||
end
|
||||
|
||||
def self.find_bookings_needing_sessions(minimum_start_time)
|
||||
MusicSession.select([:lesson_booking_id]).joins(:lesson_session => :lesson_booking).where("lesson_bookings.active = true").where('lesson_bookings.recurring = true').where("scheduled_start is not null").where("scheduled_start > ?", minimum_start_time).group(:lesson_booking_id).having('count(lesson_booking_id) < 2')
|
||||
|
|
@ -806,7 +871,6 @@ module JamRuby
|
|||
end
|
||||
end
|
||||
|
||||
|
||||
def home_url
|
||||
APP_CONFIG.external_root_url + "/client#/jamclass"
|
||||
end
|
||||
|
|
|
|||
|
|
@ -73,25 +73,44 @@ module JamRuby
|
|||
|
||||
def scheduled_times(needed_sessions, minimum_start_time)
|
||||
|
||||
#puts "NEEDED SESSIONS #{needed_sessions} #{minimum_start_time}"
|
||||
times = []
|
||||
week_offset = 0
|
||||
|
||||
needed_sessions.times do |i|
|
||||
candidate = scheduled_time(i + week_offset)
|
||||
|
||||
#puts "#{i}: candidate #{candidate} week_offset:#{week_offset}"
|
||||
if day_of_week && candidate <= minimum_start_time
|
||||
# move it up a week
|
||||
week_offset += 1
|
||||
candidate = scheduled_time(i + week_offset)
|
||||
|
||||
#puts "retry #1 #{candidate}"
|
||||
# sanity check
|
||||
if candidate <= minimum_start_time
|
||||
week_offset += 1
|
||||
candidate = scheduled_time(i + week_offset)
|
||||
|
||||
#puts "retry #2 #{candidate}"
|
||||
if candidate <= minimum_start_time
|
||||
raise "candidate time less than minimum start time even after scoot: #{lesson_booking.id} #{self.id}"
|
||||
|
||||
week_offset += 1
|
||||
candidate = scheduled_time(i + week_offset)
|
||||
|
||||
#puts "retry #3 #{candidate}"
|
||||
if candidate <= minimum_start_time
|
||||
|
||||
week_offset += 1
|
||||
candidate = scheduled_time(i + week_offset)
|
||||
|
||||
#puts "retry #4 #{candidate}"
|
||||
if candidate <= minimum_start_time
|
||||
raise "candidate time less than minimum start time even after scoot: #{lesson_booking.id} #{self.id}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
times << candidate
|
||||
|
|
|
|||
|
|
@ -26,23 +26,26 @@ module JamRuby
|
|||
|
||||
def validate_test_drive
|
||||
if user
|
||||
if !user.can_buy_test_drive?
|
||||
if lesson_package_type.is_test_drive? && !user.can_buy_test_drive?
|
||||
errors.add(:user, "can not buy test drive right now because you have already purchased it within the last year")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def create_charge
|
||||
self.lesson_payment_charge = LessonPaymentCharge.new
|
||||
lesson_payment_charge.amount_in_cents = 0
|
||||
lesson_payment_charge.fee_in_cents = 0
|
||||
lesson_payment_charge.lesson_package_purchase = self
|
||||
lesson_payment_charge.save!
|
||||
if !school_on_school? && lesson_booking && lesson_booking.is_monthly_payment?
|
||||
self.lesson_payment_charge = LessonPaymentCharge.new
|
||||
lesson_payment_charge.user = user
|
||||
lesson_payment_charge.amount_in_cents = 0
|
||||
lesson_payment_charge.fee_in_cents = 0
|
||||
lesson_payment_charge.lesson_package_purchase = self
|
||||
lesson_payment_charge.save!
|
||||
end
|
||||
end
|
||||
|
||||
def add_test_drives
|
||||
if self.lesson_package_type.is_test_drive?
|
||||
new_test_drives = user.remaining_test_drives + 4
|
||||
new_test_drives = user.remaining_test_drives + lesson_package_type.test_drive_count
|
||||
User.where(id: user.id).update_all(remaining_test_drives: new_test_drives)
|
||||
user.remaining_test_drives = new_test_drives
|
||||
end
|
||||
|
|
@ -71,17 +74,19 @@ module JamRuby
|
|||
|
||||
if lesson_booking && lesson_booking.requires_teacher_distribution?(purchase)
|
||||
purchase.teacher_distribution = TeacherDistribution.create_for_lesson_package_purchase(purchase)
|
||||
# price should always match the teacher_distribution, if there is one
|
||||
purchase.price = purchase.teacher_distribution.amount_in_cents / 100
|
||||
end
|
||||
else
|
||||
purchase.recurring = false
|
||||
end
|
||||
|
||||
if lesson_booking
|
||||
purchase.lesson_package_type = lesson_booking.lesson_package_type
|
||||
purchase.price = lesson_booking.booked_price # lesson_package_type.booked_price(lesson_booking)
|
||||
purchase.lesson_package_type = lesson_package_type ? lesson_package_type : lesson_booking.lesson_package_type
|
||||
purchase.price = lesson_booking.booked_price if purchase.price.nil?
|
||||
else
|
||||
purchase.lesson_package_type = lesson_package_type
|
||||
purchase.price = lesson_package_type.price
|
||||
purchase.price = lesson_package_type.price if purchase.price.nil?
|
||||
end
|
||||
|
||||
purchase.save
|
||||
|
|
@ -100,6 +105,9 @@ module JamRuby
|
|||
description(lesson_booking)
|
||||
end
|
||||
|
||||
def timed_description
|
||||
"Lessons for the month of #{self.month_name} with #{self.lesson_booking.student.name}"
|
||||
end
|
||||
|
||||
def month_name
|
||||
if recurring
|
||||
|
|
@ -113,11 +121,21 @@ module JamRuby
|
|||
user
|
||||
end
|
||||
|
||||
def school_on_school?
|
||||
teacher.teacher.school && student.school && (teacher.teacher.school.id == student.school.id)
|
||||
end
|
||||
|
||||
|
||||
def bill_monthly(force = false)
|
||||
lesson_payment_charge.charge(force)
|
||||
|
||||
if lesson_payment_charge.billed
|
||||
if school_on_school?
|
||||
success = true
|
||||
else
|
||||
lesson_payment_charge.charge(force)
|
||||
success = lesson_payment_charge.billed
|
||||
end
|
||||
|
||||
if success
|
||||
self.sent_notices = true
|
||||
self.sent_notices_at = Time.now
|
||||
self.post_processed = true
|
||||
|
|
|
|||
|
|
@ -7,21 +7,29 @@ module JamRuby
|
|||
PRODUCT_TYPE = 'LessonPackageType'
|
||||
|
||||
SINGLE_FREE = 'single-free'
|
||||
TEST_DRIVE = 'test-drive'
|
||||
TEST_DRIVE_4 = 'test-drive'
|
||||
TEST_DRIVE_2 = 'test-drive-2'
|
||||
TEST_DRIVE_1 = 'test-drive-1'
|
||||
SINGLE = 'single'
|
||||
|
||||
LESSON_PACKAGE_TYPES =
|
||||
[
|
||||
SINGLE_FREE,
|
||||
TEST_DRIVE,
|
||||
TEST_DRIVE_4,
|
||||
TEST_DRIVE_2,
|
||||
TEST_DRIVE_1,
|
||||
SINGLE
|
||||
]
|
||||
|
||||
has_many :user_desired_packages, class_name: "JamRuby::User", :foreign_key => "lesson_package_type_id", inverse_of: :desired_package
|
||||
validates :name, presence: true
|
||||
validates :description, presence: true
|
||||
validates :price, presence: true
|
||||
validates :package_type, presence: true, inclusion: {in: LESSON_PACKAGE_TYPES}
|
||||
|
||||
def self.test_drive_package_ids
|
||||
[TEST_DRIVE_4, TEST_DRIVE_2, TEST_DRIVE_1]
|
||||
end
|
||||
def self.monthly
|
||||
LessonPackageType.find(MONTHLY)
|
||||
end
|
||||
|
|
@ -30,8 +38,16 @@ module JamRuby
|
|||
LessonPackageType.find(SINGLE_FREE)
|
||||
end
|
||||
|
||||
def self.test_drive
|
||||
LessonPackageType.find(TEST_DRIVE)
|
||||
def self.test_drive_4
|
||||
LessonPackageType.find(TEST_DRIVE_4)
|
||||
end
|
||||
|
||||
def self.test_drive_2
|
||||
LessonPackageType.find(TEST_DRIVE_2)
|
||||
end
|
||||
|
||||
def self.test_drive_1
|
||||
LessonPackageType.find(TEST_DRIVE_1)
|
||||
end
|
||||
|
||||
def self.single
|
||||
|
|
@ -42,17 +58,21 @@ module JamRuby
|
|||
if is_single_free?
|
||||
0
|
||||
elsif is_test_drive?
|
||||
LessonPackageType.test_drive.price
|
||||
10.00
|
||||
elsif is_normal?
|
||||
lesson_booking.booked_price #teacher.teacher.booking_price(lesson_booking.lesson_length, lesson_booking.payment_style == LessonBooking::PAYMENT_STYLE_SINGLE)
|
||||
end
|
||||
end
|
||||
|
||||
def test_drive_count
|
||||
package_type["test-drive-".length, 1].to_i
|
||||
end
|
||||
|
||||
def description(lesson_booking)
|
||||
if is_single_free?
|
||||
"Single Free Lesson"
|
||||
elsif is_test_drive?
|
||||
"Test Drive"
|
||||
"Test Drive (#{test_drive_count})"
|
||||
elsif is_normal?
|
||||
if lesson_booking.recurring
|
||||
"Recurring #{lesson_booking.payment_style == LessonBooking::PAYMENT_STYLE_WEEKLY ? "Weekly" : "Monthly"} #{lesson_booking.lesson_length}m"
|
||||
|
|
@ -71,7 +91,7 @@ module JamRuby
|
|||
end
|
||||
|
||||
def is_test_drive?
|
||||
id == TEST_DRIVE
|
||||
id.start_with?('test-drive')
|
||||
end
|
||||
|
||||
def is_normal?
|
||||
|
|
@ -86,8 +106,12 @@ module JamRuby
|
|||
def plan_code
|
||||
if package_type == SINGLE_FREE
|
||||
"lesson-package-single-free"
|
||||
elsif package_type == TEST_DRIVE
|
||||
"lesson-package-test-drive"
|
||||
elsif package_type == 'test-drive-4'
|
||||
"lesson-package-test-drive-4"
|
||||
elsif package_type == TEST_DRIVE_2
|
||||
"lesson-package-test-drive-2"
|
||||
elsif package_type == TEST_DRIVE_1
|
||||
"lesson-package-test-drive-1"
|
||||
elsif package_type == SINGLE
|
||||
"lesson-package-single"
|
||||
else
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ module JamRuby
|
|||
end
|
||||
|
||||
def charged_user
|
||||
@charged_user ||= target.student
|
||||
user
|
||||
end
|
||||
|
||||
def resolve_target
|
||||
|
|
@ -31,6 +31,10 @@ module JamRuby
|
|||
charged_user
|
||||
end
|
||||
|
||||
def teacher
|
||||
target.teacher
|
||||
end
|
||||
|
||||
def is_lesson?
|
||||
!lesson_session.nil?
|
||||
end
|
||||
|
|
@ -85,5 +89,13 @@ module JamRuby
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
def description
|
||||
target.timed_description
|
||||
end
|
||||
|
||||
def expected_price_in_cents
|
||||
target.lesson_booking.distribution_price_in_cents(target)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -5,13 +5,13 @@ module JamRuby
|
|||
include HtmlSanitize
|
||||
html_sanitize strict: [:cancel_message]
|
||||
|
||||
attr_accessor :accepting, :creating, :countering, :countered_slot, :countered_lesson, :canceling
|
||||
attr_accessor :accepting, :creating, :countering, :countered_slot, :countered_lesson, :canceling, :assigned_student
|
||||
|
||||
|
||||
@@log = Logging.logger[LessonSession]
|
||||
|
||||
delegate :sent_billing_notices, :last_billing_attempt_at, :billing_attempts, :billing_should_retry, :billed, :billed_at, :billing_error_detail, :billing_error_reason, :is_card_declined?, :is_card_expired?, :last_billed_at_date, :sent_billing_notices, to: :lesson_payment_charge
|
||||
delegate :is_test_drive?, :is_single_free?, :is_normal?, :approved_before?, :is_active?, to: :lesson_booking
|
||||
delegate :sent_billing_notices, :last_billing_attempt_at, :billing_attempts, :billing_should_retry, :billed_at, :billing_error_detail, :billing_error_reason, :is_card_declined?, :is_card_expired?, :last_billed_at_date, :sent_billing_notices, to: :lesson_payment_charge, allow_nil: true
|
||||
delegate :is_test_drive?, :is_single_free?, :is_normal?, :approved_before?, :is_active?, :recurring, :is_monthly_payment?, to: :lesson_booking
|
||||
delegate :pretty_scheduled_start, to: :music_session
|
||||
|
||||
|
||||
|
|
@ -30,16 +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"
|
||||
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
|
||||
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
|
||||
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}
|
||||
|
|
@ -69,10 +71,13 @@ module JamRuby
|
|||
scope :suspended, -> { where(status: STATUS_SUSPENDED) }
|
||||
scope :completed, -> { where(status: STATUS_COMPLETED) }
|
||||
scope :missed, -> { where(status: STATUS_MISSED) }
|
||||
scope :upcoming, -> { joins(:music_session).where('music_sessions.scheduled_start > ?', Time.now) }
|
||||
scope :past_cancel_window, -> { joins(:music_session).where('music_sessions.scheduled_start > ?', 24.hours.from_now) }
|
||||
|
||||
def create_charge
|
||||
if !is_test_drive?
|
||||
if !school_on_school? && !is_test_drive? && !is_monthly_payment?
|
||||
self.lesson_payment_charge = LessonPaymentCharge.new
|
||||
lesson_payment_charge.user = @assigned_student
|
||||
lesson_payment_charge.amount_in_cents = 0
|
||||
lesson_payment_charge.fee_in_cents = 0
|
||||
lesson_payment_charge.lesson_session = self
|
||||
|
|
@ -96,23 +101,52 @@ module JamRuby
|
|||
self.save
|
||||
end
|
||||
|
||||
def music_session_id
|
||||
music_session.id
|
||||
end
|
||||
|
||||
def self.hourly_check
|
||||
analyse_sessions
|
||||
complete_sessions
|
||||
end
|
||||
|
||||
def self.minutely_check
|
||||
upcoming_sessions_reminder
|
||||
end
|
||||
|
||||
def self.analyse_sessions
|
||||
MusicSession.joins(lesson_session: :lesson_booking).where('session_removed_at IS NOT NULL').where('analysed = false').each do |music_session|
|
||||
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|
|
||||
lession_session = music_session.lesson_session
|
||||
lession_session.analyse
|
||||
end
|
||||
end
|
||||
|
||||
def self.complete_sessions
|
||||
MusicSession.joins(lesson_session: [:lesson_booking, :lesson_payment_charge]).where('session_removed_at IS NOT NULL').where('analysed = true').where('lesson_sessions.post_processed = false').where('billing_should_retry = true').each do |music_session|
|
||||
# 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|
|
||||
lession_session = music_session.lesson_session
|
||||
lession_session.session_completed
|
||||
end
|
||||
|
||||
# test drives don't have a lesson_payment_charge, so we don't join against them
|
||||
MusicSession.joins(lesson_session: [:lesson_booking]).where('lesson_sessions.status = ?', LessonSession::STATUS_COMPLETED).where('lesson_sessions.lesson_type = ?', LESSON_TYPE_TEST_DRIVE).where("session_removed_at IS NOT NULL OR NOW() > scheduled_start + (INTERVAL '1 minutes' * duration)").where('analysed = true').where('lesson_sessions.post_processed = false').each do |music_session|
|
||||
lession_session = music_session.lesson_session
|
||||
lession_session.session_completed
|
||||
end
|
||||
end
|
||||
|
||||
def self.upcoming_sessions_reminder
|
||||
now = Time.now
|
||||
half_hour_from_now = 30.minutes.from_now
|
||||
if Time.zone
|
||||
now = Time.zone.local_to_utc(now)
|
||||
half_hour_from_now = Time.zone.local_to_utc(half_hour_from_now)
|
||||
end
|
||||
|
||||
MusicSession.joins(lesson_session: [:lesson_booking]).where('lesson_sessions.status = ?', LessonSession::STATUS_APPROVED).where('sent_starting_notice = false').where('(scheduled_start > ? and scheduled_start < ?)', now, half_hour_from_now).each do |music_session|
|
||||
lession_session = music_session.lesson_session
|
||||
lession_session.send_starting_notice
|
||||
end
|
||||
end
|
||||
|
||||
def analyse
|
||||
|
|
@ -122,12 +156,14 @@ module JamRuby
|
|||
|
||||
analysis = LessonSessionAnalyser.analyse(self)
|
||||
|
||||
self.analysis = analysis_to_json(analysis)
|
||||
self.analysis = LessonSession.analysis_to_json(analysis)
|
||||
self.success = analysis[:bill]
|
||||
self.analysed_at = Time.now
|
||||
self.analysed = true
|
||||
|
||||
if lesson_booking.requires_teacher_distribution?(self)
|
||||
self.status = STATUS_COMPLETED
|
||||
|
||||
if success && lesson_booking.requires_teacher_distribution?(self)
|
||||
self.teacher_distribution = TeacherDistribution.create_for_lesson(self)
|
||||
end
|
||||
|
||||
|
|
@ -137,12 +173,19 @@ module JamRuby
|
|||
end
|
||||
end
|
||||
|
||||
def billed
|
||||
if lesson_booking.is_test_drive?
|
||||
false
|
||||
else
|
||||
lesson_payment_charge.billed
|
||||
end
|
||||
end
|
||||
|
||||
def amount_charged
|
||||
lesson_payment_charge.amount_in_cents / 100.0
|
||||
end
|
||||
|
||||
def analysis_to_json(analysis)
|
||||
def self.analysis_to_json(analysis, preserve_object = false)
|
||||
json = {}
|
||||
|
||||
analysis.each do |k, v|
|
||||
|
|
@ -160,7 +203,19 @@ module JamRuby
|
|||
json[k] = v
|
||||
end
|
||||
end
|
||||
json.to_json
|
||||
if preserve_object
|
||||
json
|
||||
else
|
||||
json.to_json
|
||||
end
|
||||
end
|
||||
|
||||
def send_starting_notice
|
||||
UserMailer.lesson_starting_soon_student(self).deliver!
|
||||
UserMailer.lesson_starting_soon_teacher(self).deliver!
|
||||
|
||||
self.sent_starting_notice = true
|
||||
self.save(validate: false)
|
||||
end
|
||||
|
||||
def session_completed
|
||||
|
|
@ -186,10 +241,14 @@ module JamRuby
|
|||
end
|
||||
|
||||
def bill_lesson
|
||||
if school_on_school?
|
||||
success = true
|
||||
else
|
||||
lesson_payment_charge.charge
|
||||
success = lesson_payment_charge.billed
|
||||
end
|
||||
|
||||
lesson_payment_charge.charge
|
||||
|
||||
if lesson_payment_charge.billed
|
||||
if success
|
||||
self.sent_notices = true
|
||||
self.sent_notices_at = Time.now
|
||||
self.post_processed = true
|
||||
|
|
@ -202,13 +261,13 @@ module JamRuby
|
|||
def test_drive_completed
|
||||
|
||||
distribution = teacher_distribution
|
||||
if distribution # not all lessons/payment charges have a distribution
|
||||
distribution.ready = true
|
||||
distribution.save(validate: false)
|
||||
end
|
||||
|
||||
if !sent_notices
|
||||
if success
|
||||
if distribution # not all lessons/payment charges have a distribution
|
||||
distribution.ready = true
|
||||
distribution.save(validate: false)
|
||||
end
|
||||
student.test_drive_succeeded(self)
|
||||
else
|
||||
student.test_drive_failed(self)
|
||||
|
|
@ -242,9 +301,12 @@ module JamRuby
|
|||
end
|
||||
else
|
||||
if lesson_booking.is_monthly_payment?
|
||||
# bad session; just poke user
|
||||
if !sent_notices
|
||||
UserMailer.monthly_recurring_no_bill(self).deliver
|
||||
if !school_on_school?
|
||||
# bad session; just poke user
|
||||
UserMailer.monthly_recurring_no_bill(self).deliver
|
||||
end
|
||||
|
||||
self.sent_notices = true
|
||||
self.sent_notices_at = Time.now
|
||||
self.post_processed = true
|
||||
|
|
@ -254,8 +316,11 @@ module JamRuby
|
|||
|
||||
else
|
||||
if !sent_notices
|
||||
# bad session; just poke user
|
||||
UserMailer.student_weekly_recurring_no_bill(student, self).deliver
|
||||
if !school_on_school?
|
||||
# bad session; just poke user
|
||||
UserMailer.student_lesson_normal_no_bill(self).deliver
|
||||
end
|
||||
|
||||
self.sent_notices = true
|
||||
self.sent_notices_at = Time.now
|
||||
self.post_processed = true
|
||||
|
|
@ -272,8 +337,11 @@ module JamRuby
|
|||
bill_lesson
|
||||
else
|
||||
if !sent_notices
|
||||
UserMailer.student_lesson_normal_no_bill(self).deliver
|
||||
UserMailer.teacher_lesson_no_bill(self).deliver
|
||||
if !school_on_school?
|
||||
UserMailer.student_lesson_normal_no_bill(self).deliver
|
||||
UserMailer.teacher_lesson_normal_no_bill(self).deliver
|
||||
end
|
||||
|
||||
self.sent_notices = true
|
||||
self.sent_notices_at = Time.now
|
||||
self.post_processed = true
|
||||
|
|
@ -314,10 +382,6 @@ module JamRuby
|
|||
status == STATUS_COMPLETED
|
||||
end
|
||||
|
||||
def is_missed?
|
||||
status == STATUS_MISSED
|
||||
end
|
||||
|
||||
def is_approved?
|
||||
status == STATUS_APPROVED
|
||||
end
|
||||
|
|
@ -330,6 +394,14 @@ module JamRuby
|
|||
status == STATUS_COUNTERED
|
||||
end
|
||||
|
||||
def analysis_json
|
||||
@parsed_analysis || analysis ? JSON.parse(analysis) : nil
|
||||
end
|
||||
|
||||
def school_on_school?
|
||||
teacher.teacher.school && student.school && (teacher.teacher.school.id == student.school.id)
|
||||
end
|
||||
|
||||
def validate_creating
|
||||
if !is_requested? && !is_approved?
|
||||
self.errors.add(:status, "is not valid for a new lesson session.")
|
||||
|
|
@ -378,6 +450,7 @@ module JamRuby
|
|||
lesson_session.teacher = booking.teacher
|
||||
lesson_session.status = booking.status
|
||||
lesson_session.slot = booking.default_slot
|
||||
lesson_session.assigned_student = booking.student
|
||||
if booking.is_test_drive?
|
||||
lesson_session.lesson_package_purchase = booking.student.most_recent_test_drive_purchase
|
||||
end
|
||||
|
|
@ -393,21 +466,31 @@ module JamRuby
|
|||
music_session.creator
|
||||
end
|
||||
|
||||
def student_id
|
||||
music_session.creator.id
|
||||
end
|
||||
|
||||
def self.index(user, params = {})
|
||||
limit = params[:per_page]
|
||||
limit ||= 100
|
||||
limit = limit.to_i
|
||||
|
||||
query = LessonSession.joins(:music_session).joins(music_session: :creator)
|
||||
query = query.includes([:teacher, :music_session])
|
||||
query = LessonSession.unscoped.joins([:music_session, :lesson_booking]).joins(music_session: :creator)
|
||||
#query = query.includes([:teacher, :music_session])
|
||||
query = query.includes([:music_session])
|
||||
query = query.order('music_sessions.scheduled_start DESC')
|
||||
|
||||
if params[:as_teacher]
|
||||
query = query.where('lesson_sessions.teacher_id = ?', user.id)
|
||||
if params[:as_teacher].present?
|
||||
if params[:as_teacher]
|
||||
query = query.where('lesson_sessions.teacher_id = ?', user.id)
|
||||
else
|
||||
query = query.where('music_sessions.user_id = ?', user.id)
|
||||
end
|
||||
else
|
||||
query = query.where('music_sessions.user_id = ?', user.id)
|
||||
query = query.where('(lesson_sessions.teacher_id = ? or music_sessions.user_id = ?)', user.id, user.id)
|
||||
end
|
||||
|
||||
query = query.where('lesson_bookings.card_presumed_ok = true OR (music_sessions.user_id = ?)', user.id)
|
||||
|
||||
current_page = params[:page].nil? ? 1 : params[:page].to_i
|
||||
next_page = current_page + 1
|
||||
|
|
@ -451,6 +534,17 @@ module JamRuby
|
|||
time.nil? ? nil : attempt
|
||||
end
|
||||
|
||||
def school_owner_id
|
||||
school = teacher.teacher.school
|
||||
if school
|
||||
school.owner.id
|
||||
end
|
||||
end
|
||||
|
||||
def access?(user)
|
||||
user.id == music_session.user_id || user.id == teacher.id || user.id == school_owner_id
|
||||
end
|
||||
|
||||
# teacher accepts the lesson
|
||||
def accept(params)
|
||||
response = self
|
||||
|
|
@ -480,8 +574,8 @@ module JamRuby
|
|||
end
|
||||
UserMailer.student_lesson_accepted(self, message, slot).deliver
|
||||
UserMailer.teacher_lesson_accepted(self, message, slot).deliver
|
||||
chat_message = message ? "Lesson Approved: '#{message}'" : "Lesson Approved"
|
||||
msg = ChatMessage.create(teacher, nil, chat_message, ChatMessage::CHANNEL_LESSON, nil, student, lesson_booking)
|
||||
message = '' if message.nil?
|
||||
msg = ChatMessage.create(teacher, nil, message, ChatMessage::CHANNEL_LESSON, nil, student, self, "Lesson Approved")
|
||||
Notification.send_jamclass_invitation_teacher(music_session, teacher)
|
||||
Notification.send_student_jamclass_invitation(music_session, student)
|
||||
Notification.send_lesson_message('accept', self, true)
|
||||
|
|
@ -501,8 +595,8 @@ module JamRuby
|
|||
response = lesson_booking
|
||||
raise ActiveRecord::Rollback
|
||||
end
|
||||
chat_message = message ? "All Lesson Times Updated: '#{message}'" : "All Lesson Times Updated"
|
||||
msg = ChatMessage.create(slot.proposer, nil, chat_message, ChatMessage::CHANNEL_LESSON, nil, slot.recipient, lesson_booking)
|
||||
message = '' if message.nil?
|
||||
msg = ChatMessage.create(slot.proposer, nil, message, ChatMessage::CHANNEL_LESSON, nil, slot.recipient, self, "All Lesson Times Updated")
|
||||
Notification.send_lesson_message('accept', self, true) # TODO: this isn't quite an 'accept'
|
||||
UserMailer.student_lesson_update_all(self, message, slot).deliver
|
||||
UserMailer.teacher_lesson_update_all(self, message, slot).deliver
|
||||
|
|
@ -515,8 +609,8 @@ module JamRuby
|
|||
puts("unable to accept slot #{slot.id} for lesson #{self.id} because it's in the past")
|
||||
raise ActiveRecord::Rollback
|
||||
end
|
||||
chat_message = message ? "Lesson Updated Time Approved: '#{message}'" : "Lesson Updated Time Approved"
|
||||
msg = ChatMessage.create(slot.proposer, nil, chat_message, ChatMessage::CHANNEL_LESSON, nil, slot.recipient, lesson_booking)
|
||||
message = '' if message.nil?
|
||||
msg = ChatMessage.create(slot.proposer, nil, message, ChatMessage::CHANNEL_LESSON, nil, slot.recipient, self, "Lesson Updated Time Approved")
|
||||
UserMailer.student_lesson_accepted(self, message, slot).deliver
|
||||
UserMailer.teacher_lesson_accepted(self, message, slot).deliver
|
||||
end
|
||||
|
|
@ -551,25 +645,42 @@ module JamRuby
|
|||
self.counter_slot = slot
|
||||
end
|
||||
if self.save
|
||||
if update_all
|
||||
if !lesson_booking.counter(self, proposer, slot)
|
||||
response = lesson_booking
|
||||
raise ActiveRecord::Rollback
|
||||
end
|
||||
if update_all && !lesson_booking.counter(self, proposer, slot)
|
||||
response = lesson_booking
|
||||
raise ActiveRecord::Rollback
|
||||
end
|
||||
else
|
||||
response = self
|
||||
raise ActiveRecord::Rollback
|
||||
end
|
||||
|
||||
|
||||
msg = ChatMessage.create(slot.proposer, music_session, message, ChatMessage::CHANNEL_LESSON, nil, slot.recipient, lesson_booking)
|
||||
message = '' if message.nil?
|
||||
msg = ChatMessage.create(slot.proposer, music_session, message, ChatMessage::CHANNEL_LESSON, nil, slot.recipient, self, "New Time Proposed")
|
||||
Notification.send_lesson_message('counter', self, slot.is_teacher_created?)
|
||||
end
|
||||
|
||||
response
|
||||
end
|
||||
|
||||
def cancel_lesson(canceler, message)
|
||||
canceled_by_student = canceler == student
|
||||
self.status = STATUS_CANCELED
|
||||
self.cancel_message = message
|
||||
self.canceler = canceler
|
||||
self.canceling = true
|
||||
|
||||
if canceled_by_student
|
||||
self.student_canceled = true
|
||||
self.student_canceled_at = Time.now
|
||||
self.student_canceled_reason = message
|
||||
self.student_short_canceled = 24.hours.from_now > scheduled_start
|
||||
else
|
||||
self.teacher_canceled = true
|
||||
self.teacher_canceled_at = Time.now
|
||||
self.teacher_canceled_reason = message
|
||||
self.teacher_short_canceled = 24.hours.from_now > scheduled_start
|
||||
end
|
||||
end
|
||||
|
||||
# teacher accepts the lesson
|
||||
def cancel(params)
|
||||
|
|
@ -577,39 +688,39 @@ module JamRuby
|
|||
LessonSession.transaction do
|
||||
|
||||
canceler = params[:canceler]
|
||||
other = canceler == teacher ? student : teacher
|
||||
canceled_by_student = canceler == student
|
||||
other = canceled_by_student ? teacher : student
|
||||
message = params[:message]
|
||||
message = '' if message.nil?
|
||||
|
||||
if params[:update_all].present?
|
||||
if lesson_booking.recurring
|
||||
update_all = params[:update_all]
|
||||
else
|
||||
update_all = !lesson_booking.recurring
|
||||
update_all = true
|
||||
end
|
||||
|
||||
if lesson_booking.is_test_drive?
|
||||
student.test_drive_declined(self)
|
||||
end
|
||||
|
||||
self.status = STATUS_CANCELED
|
||||
self.cancel_message = message
|
||||
self.canceler = canceler
|
||||
self.canceling = true
|
||||
|
||||
if self.save
|
||||
if update_all
|
||||
if !lesson_booking.cancel(canceler, other, message)
|
||||
response = lesson_booking
|
||||
raise ActiveRecord::Rollback
|
||||
end
|
||||
else
|
||||
msg = ChatMessage.create(canceler, nil, message, ChatMessage::CHANNEL_LESSON, nil, other, lesson_booking)
|
||||
Notification.send_lesson_message('canceled', self, false)
|
||||
Notification.send_lesson_message('canceled', self, true)
|
||||
UserMailer.student_lesson_canceled(self, message).deliver
|
||||
UserMailer.teacher_lesson_canceled(self, message).deliver
|
||||
if update_all
|
||||
response = lesson_booking.cancel(canceler, other, message)
|
||||
if response.errors.any?
|
||||
raise ActiveRecord::Rollback
|
||||
end
|
||||
else
|
||||
response = self
|
||||
raise ActiveRecord::Rollback
|
||||
end
|
||||
cancel_lesson(canceler, message)
|
||||
if !save
|
||||
response = self
|
||||
raise ActiveRecord::Rollback
|
||||
end
|
||||
|
||||
msg = ChatMessage.create(canceler, nil, message, ChatMessage::CHANNEL_LESSON, nil, other, self, "Lesson Canceled")
|
||||
Notification.send_lesson_message('canceled', self, false)
|
||||
Notification.send_lesson_message('canceled', self, true)
|
||||
UserMailer.student_lesson_canceled(self, message).deliver
|
||||
UserMailer.teacher_lesson_canceled(self, message).deliver
|
||||
end
|
||||
end
|
||||
|
||||
response
|
||||
|
|
@ -619,6 +730,19 @@ module JamRuby
|
|||
lesson_booking.lesson_package_type.description(lesson_booking)
|
||||
end
|
||||
|
||||
def timed_description
|
||||
if is_test_drive?
|
||||
"TestDrive session with #{self.lesson_booking.student.name} on #{self.scheduled_start.to_date.strftime('%B %d, %Y')}"
|
||||
else
|
||||
if self.lesson_booking.is_monthly_payment?
|
||||
"Monthly Lesson with #{self.lesson_booking.student.name} on #{self.scheduled_start.to_date.strftime('%B %d, %Y')}"
|
||||
else
|
||||
"Lesson with #{self.lesson_booking.student.name} on #{self.scheduled_start.to_date.strftime('%B %d, %Y')}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def stripe_description(lesson_booking)
|
||||
description(lesson_booking)
|
||||
end
|
||||
|
|
@ -638,5 +762,9 @@ module JamRuby
|
|||
def admin_url
|
||||
APP_CONFIG.admin_root_url + "/admin/lesson_sessions/" + id
|
||||
end
|
||||
|
||||
def chat_url
|
||||
APP_CONFIG.external_root_url + "/client#/jamclass/chat-dialog/d1=lesson_" + id
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
module JamRuby
|
||||
class LessonSessionAnalyser
|
||||
|
||||
SUCCESS = 'success'
|
||||
SUCCESS = 'success'
|
||||
SESSION_ONGOING = 'session_ongoing'
|
||||
THRESHOLD_MET = 'threshold_met'
|
||||
WAITED_CORRECTLY = 'waited_correctly'
|
||||
|
|
@ -16,6 +16,7 @@ module JamRuby
|
|||
STUDENT_NOT_THERE_WHEN_JOINED = 'student_not_there_when_joined'
|
||||
JOINED_LATE = 'did_not_join_on_time'
|
||||
NO_SHOW = 'no_show'
|
||||
NEITHER_SHOW = 'neither_show'
|
||||
|
||||
|
||||
# what are the potential results?
|
||||
|
|
@ -42,7 +43,7 @@ module JamRuby
|
|||
# reason: 'both_fault'
|
||||
|
||||
|
||||
def self.analyse(lesson_session)
|
||||
def self.analyse(lesson_session, force = false)
|
||||
reason = nil
|
||||
teacher = nil
|
||||
student = nil
|
||||
|
|
@ -62,26 +63,25 @@ module JamRuby
|
|||
teacher_ranges = merge_overlapping_ranges(all_teacher_ranges)
|
||||
|
||||
intersecting = intersecting_ranges(student_ranges, teacher_ranges)
|
||||
|
||||
student_analysis = analyse_intersection(lesson_session, student_ranges)
|
||||
teacher_analysis = analyse_intersection(lesson_session, teacher_ranges)
|
||||
together_analysis = analyse_intersection(lesson_session, intersecting)
|
||||
|
||||
# spec: https://jamkazam.atlassian.net/wiki/display/PS/Product+Specification+-+JamClass#ProductSpecification-JamClass-TeacherReceives&RespondstoLessonBookingRequest
|
||||
|
||||
if music_session.session_removed_at.nil?
|
||||
if !force && !((music_session.scheduled_start + (lesson_session.duration * 60)) < Time.now)
|
||||
reason = SESSION_ONGOING
|
||||
bill = false
|
||||
else
|
||||
if lesson_session.is_canceled? && lesson_session.canceled_by_teacher? && lesson_session.canceled_late?
|
||||
# If the lesson was cancelled less than 24 hours before the start time by the teacher, then we do not bill the student.
|
||||
teacher = LATE_CANCELLATION
|
||||
bill = false
|
||||
elsif lesson_session.is_canceled? && lesson_session.canceled_by_student? && lesson_session.canceled_late?
|
||||
# If the lesson was cancelled less than 24 hours before the start time by the student (if that is even possible, I can’t remember now), then we do bill the student.
|
||||
student = LATE_CANCELLATION
|
||||
bill = true
|
||||
elsif together_analysis[:session_time] / 60 > APP_CONFIG.lesson_together_threshold_minutes
|
||||
#if lesson_session.is_canceled? && lesson_session.canceled_by_teacher? && lesson_session.canceled_late?
|
||||
# # If the lesson was cancelled less than 24 hours before the start time by the teacher, then we do not bill the student.
|
||||
# teacher = LATE_CANCELLATION
|
||||
# bill = false
|
||||
#elsif lesson_session.is_canceled? && lesson_session.canceled_by_student? && lesson_session.canceled_late?
|
||||
# # If the lesson was cancelled less than 24 hours before the start time by the student (if that is even possible, I can’t remember now), then we do bill the student.
|
||||
# student = LATE_CANCELLATION
|
||||
# bill = true
|
||||
if together_analysis[:session_time] / 60 > APP_CONFIG.lesson_together_threshold_minutes
|
||||
bill = true
|
||||
reason = SUCCESS
|
||||
elsif teacher_analysis[:joined_on_time] && teacher_analysis[:waited_correctly]
|
||||
|
|
@ -98,8 +98,17 @@ module JamRuby
|
|||
student = JOINED_LATE
|
||||
bill = true
|
||||
end
|
||||
else
|
||||
if teacher_analysis[:no_show]
|
||||
teacher = NO_SHOW
|
||||
elsif !teacher_analysis[:joined_on_time]
|
||||
teacher = JOINED_LATE
|
||||
elsif !teacher_analysis[:waited_correctly]
|
||||
teacher = MINIMUM_TIME_NOT_MET
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
if reason.nil?
|
||||
|
|
@ -107,6 +116,8 @@ module JamRuby
|
|||
reason = STUDENT_FAULT
|
||||
elsif teacher
|
||||
reason = TEACHER_FAULT
|
||||
else
|
||||
reason = NEITHER_SHOW
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -150,7 +161,8 @@ module JamRuby
|
|||
|
||||
|
||||
def self.analyse_intersection(lesson_session, ranges)
|
||||
start = lesson_session.scheduled_start
|
||||
# be sure to call .to_time on any ActiveRecord time, because we get a ton of deprecation warninsg about Time#succ if you use ActiveSupport:: TimeZone
|
||||
start = lesson_session.scheduled_start.to_time
|
||||
planned_duration_seconds = lesson_session.duration * 60
|
||||
end_time = start + planned_duration_seconds
|
||||
|
||||
|
|
@ -286,7 +298,7 @@ module JamRuby
|
|||
end
|
||||
|
||||
def self.ranges_overlap?(a, b)
|
||||
a.include?(b.begin) || b.include?(a.begin)
|
||||
a.cover?(b.begin) || b.cover?(a.begin)
|
||||
end
|
||||
|
||||
def self.merge_ranges(a, b)
|
||||
|
|
|
|||
|
|
@ -6,7 +6,19 @@ module JamRuby
|
|||
|
||||
raise "lesson_booking is not monthly paid #{lesson_booking.admin_url}" if !lesson_booking.is_monthly_payment?
|
||||
|
||||
times = lesson_booking.predicted_times_for_month(start_day.year, start_day.month)
|
||||
data = lesson_booking.predicted_times_for_month(start_day.year, start_day.month)
|
||||
|
||||
times = data[:times]
|
||||
session = data[:session]
|
||||
|
||||
true_start = start_day
|
||||
if session
|
||||
# if there is already a session for the month, that is the real star
|
||||
true_start = session.scheduled_start.to_date
|
||||
end
|
||||
|
||||
# filter out anything before the start day
|
||||
times.select! { |time| time.to_date >= true_start }
|
||||
|
||||
result = nil
|
||||
if times.length == 0
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ module JamRuby
|
|||
CREATE_TYPE_IMMEDIATE = 'immediately'
|
||||
CREATE_TYPE_QUICK_START = 'quick-start'
|
||||
CREATE_TYPE_LESSON = 'lesson'
|
||||
CREATE_TYPE_QUICK_PUBLIC = 'quick-public'
|
||||
|
||||
attr_accessor :legal_terms, :language_description, :access_description, :scheduling_info_changed
|
||||
|
||||
|
|
@ -323,11 +324,29 @@ module JamRuby
|
|||
# let session be restarted for up to 2 hours after finishing
|
||||
session_finished = "(music_sessions.session_removed_at > NOW() - '2 hour'::INTERVAL)"
|
||||
|
||||
query = MusicSession.where("music_sessions.canceled = FALSE")
|
||||
query = MusicSession.joins(
|
||||
%Q{
|
||||
LEFT OUTER JOIN
|
||||
invitations
|
||||
ON
|
||||
music_sessions.id = invitations.music_session_id AND invitations.receiver_id = '#{user.id}'
|
||||
}
|
||||
)
|
||||
query = query.where("music_sessions.canceled = FALSE")
|
||||
query = query.where('music_sessions.fan_access = TRUE or music_sessions.musician_access = TRUE') if only_public
|
||||
query = query.where("music_sessions.user_id = '#{user.id}'")
|
||||
#query = query.where("music_sessions.user_id = '#{user.id}' OR invitations.id IS NOT NULL")
|
||||
query = query.where("music_sessions.id in (
|
||||
select distinct(rs.music_session_id)
|
||||
from rsvp_slots rs
|
||||
where rs.id in (
|
||||
select rrrs.rsvp_slot_id
|
||||
from rsvp_requests rr
|
||||
inner join rsvp_requests_rsvp_slots rrrs on rr.id = rrrs.rsvp_request_id
|
||||
where rr.user_id = '#{user.id}'AND rrrs.chosen = true
|
||||
)
|
||||
) OR invitations.id IS NOT NULL OR music_sessions.user_id = '#{user.id}'")
|
||||
query = query.where("music_sessions.scheduled_start IS NULL OR #{session_not_started} OR #{session_finished} OR #{session_started_not_finished}")
|
||||
query = query.where("music_sessions.create_type IS NULL OR music_sessions.create_type != '#{CREATE_TYPE_QUICK_START}'")
|
||||
query = query.where("music_sessions.create_type IS NULL OR (music_sessions.create_type != '#{CREATE_TYPE_QUICK_START}' AND music_sessions.create_type != '#{CREATE_TYPE_QUICK_PUBLIC}')")
|
||||
query = query.order("music_sessions.scheduled_start ASC")
|
||||
|
||||
query
|
||||
|
|
@ -339,7 +358,7 @@ module JamRuby
|
|||
filter_approved = only_approved ? 'AND rrrs.chosen = true' : ''
|
||||
|
||||
MusicSession.where(%Q{music_sessions.canceled = FALSE AND
|
||||
(music_sessions.create_type is NULL OR music_sessions.create_type != '#{CREATE_TYPE_QUICK_START}') AND
|
||||
(music_sessions.create_type is NULL OR (music_sessions.create_type != '#{CREATE_TYPE_QUICK_START}' AND music_sessions.create_type != '#{CREATE_TYPE_QUICK_PUBLIC}')) AND
|
||||
(music_sessions.scheduled_start is NULL OR music_sessions.scheduled_start > NOW() - '4 hour'::INTERVAL) AND
|
||||
music_sessions.id in (
|
||||
select distinct(rs.music_session_id)
|
||||
|
|
@ -760,7 +779,7 @@ module JamRuby
|
|||
|
||||
query = query.offset(offset)
|
||||
query = query.limit(limit)
|
||||
query = query.where("music_sessions.create_type IS NULL OR (music_sessions.create_type != ? AND music_sessions.create_type != ?)", MusicSession::CREATE_TYPE_QUICK_START, MusicSession::CREATE_TYPE_IMMEDIATE)
|
||||
query = query.where("music_sessions.create_type IS NULL OR (music_sessions.create_type != ? AND music_sessions.create_type != ? AND music_sessions.create_type != ?)", MusicSession::CREATE_TYPE_QUICK_START, MusicSession::CREATE_TYPE_IMMEDIATE, MusicSession::CREATE_TYPE_QUICK_PUBLIC)
|
||||
query = query.where("music_sessions.genre_id = ?", genre) unless genre.blank?
|
||||
query = query.where('music_sessions.language = ?', lang) unless lang.blank?
|
||||
query = query.where("(description_tsv @@ to_tsquery('jamenglish', ?))", ActiveRecord::Base.connection.quote(keyword) + ':*') unless keyword.blank?
|
||||
|
|
@ -875,7 +894,7 @@ SQL
|
|||
result
|
||||
end
|
||||
|
||||
def scheduled_start_date
|
||||
def scheduled_start_date
|
||||
if self.scheduled_start_time.blank?
|
||||
""
|
||||
else
|
||||
|
|
@ -936,20 +955,16 @@ SQL
|
|||
end
|
||||
duration
|
||||
end
|
||||
# should create a timestamp like:
|
||||
#
|
||||
# with_timezone = TRUE
|
||||
# Tuesday, April 29, 8:00-9:00 PM TIMEZONE (where TIMEZONE is the TIMEZONE defined in the MusicSession when it was created)
|
||||
#
|
||||
# with_timezone = FALSE
|
||||
# Thursday, July 10 - 10:00pm
|
||||
# this should be in a helper
|
||||
def pretty_scheduled_start(with_timezone = true)
|
||||
|
||||
def pretty_scheduled_start(with_timezone = true, shorter = false)
|
||||
|
||||
if scheduled_start && scheduled_duration
|
||||
start_time = scheduled_start
|
||||
timezone_display = 'UTC'
|
||||
utc_offset_display = '00:00'
|
||||
tz_identifier, tz_display = MusicSession.split_timezone(timezone)
|
||||
short_tz = 'GMT'
|
||||
|
||||
begin
|
||||
tz = TZInfo::Timezone.get(tz_identifier)
|
||||
rescue Exception => e
|
||||
|
|
@ -960,6 +975,15 @@ SQL
|
|||
begin
|
||||
start_time = tz.utc_to_local(scheduled_start.utc)
|
||||
timezone_display = tz_display
|
||||
utc_offset_hours = tz.current_period.utc_total_offset / (60*60)
|
||||
hour = sprintf '%02d', utc_offset_hours.abs
|
||||
minutes = sprintf '%02d', ((tz.current_period.utc_total_offset.abs % 3600) / 3600) * 60
|
||||
utc_offset_display = "#{utc_offset_hours < 0 ? '-' : ' '}#{hour}:#{minutes}"
|
||||
short_tz = start_time.strftime("%Z")
|
||||
if short_tz == 'UTC'
|
||||
short_tz = 'GMT'
|
||||
end
|
||||
|
||||
rescue Exception => e
|
||||
@@log.error("unable to convert #{scheduled_start} to #{tz}, e=#{e}")
|
||||
puts "unable to convert #{e}"
|
||||
|
|
@ -969,7 +993,11 @@ SQL
|
|||
duration = safe_scheduled_duration
|
||||
end_time = start_time + duration
|
||||
if with_timezone
|
||||
"#{start_time.strftime("%A, %B %e")}, #{start_time.strftime("%l:%M").strip}-#{end_time.strftime("%l:%M %p").strip} #{timezone_display}"
|
||||
if shorter
|
||||
"#{start_time.strftime("%a, %b %e %Y")}, #{start_time.strftime("%l:%M").strip}-#{end_time.strftime("%l:%M %p").strip} (#{short_tz}#{utc_offset_display})"
|
||||
else
|
||||
"#{start_time.strftime("%A, %B %e")}, #{start_time.strftime("%l:%M").strip}-#{end_time.strftime("%l:%M %p").strip} #{timezone_display}"
|
||||
end
|
||||
else
|
||||
"#{start_time.strftime("%A, %B %e")} - #{start_time.strftime("%l:%M%P").strip}"
|
||||
end
|
||||
|
|
|
|||
|
|
@ -26,7 +26,9 @@ module JamRuby
|
|||
end
|
||||
|
||||
def range
|
||||
Range.new(created_at, session_removed_at || Time.now)
|
||||
# to_time to not use ActiveSupport::TimeWithZone
|
||||
session_removed_at_time = session_removed_at.to_time if session_removed_at
|
||||
Range.new(created_at.to_time, session_removed_at_time || Time.now.to_time)
|
||||
end
|
||||
|
||||
def music_session
|
||||
|
|
@ -38,9 +40,9 @@ module JamRuby
|
|||
end
|
||||
|
||||
def self.save(music_session_id, user_id, client_id, tracks)
|
||||
return true if 0 < self.where(:music_session_id => music_session_id,
|
||||
:user_id => user_id,
|
||||
:client_id => client_id).count
|
||||
return true if 0 < self.where(:music_session_id => music_session_id,
|
||||
:user_id => user_id,
|
||||
:client_id => client_id).where('session_removed_at is NULL').count
|
||||
session_user_history = MusicSessionUserHistory.new
|
||||
session_user_history.music_session_id = music_session_id
|
||||
session_user_history.user_id = user_id
|
||||
|
|
@ -58,10 +60,12 @@ module JamRuby
|
|||
(end_time - self.created_at) / 60.0
|
||||
end
|
||||
|
||||
def self.join_music_session(user_id, session_id)
|
||||
def self.join_music_session(user_id, session_id, client_id)
|
||||
hist = self
|
||||
.where(:user_id => user_id)
|
||||
.where(:music_session_id => session_id)
|
||||
.where(:client_id => client_id)
|
||||
.where('session_removed_at IS NULL')
|
||||
.limit(1)
|
||||
.first
|
||||
hist.start_history if hist
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ module JamRuby
|
|||
end
|
||||
end
|
||||
|
||||
self.class.format_msg(self.description, {:user => source_user, target: target_user, :band => band, :session => session, purpose: purpose, student_directed: student_directed})
|
||||
self.class.format_msg(self.description, {:user => source_user, target: target_user, :band => band, :session => session, purpose: purpose, student_directed: student_directed, msg: message})
|
||||
end
|
||||
|
||||
# TODO: MAKE ALL METHODS BELOW ASYNC SO THE CLIENT DOESN'T BLOCK ON NOTIFICATION LOGIC
|
||||
|
|
@ -135,6 +135,7 @@ module JamRuby
|
|||
session = options[:session]
|
||||
purpose = options[:purpose]
|
||||
student_directed = options[:student_directed]
|
||||
msg = options[:msg]
|
||||
|
||||
name, band_name = ""
|
||||
unless user.nil?
|
||||
|
|
@ -271,6 +272,8 @@ module JamRuby
|
|||
end
|
||||
elsif purpose == 'reschedule'
|
||||
'A lesson reschedule has been requested'
|
||||
elsif purpose == 'chat'
|
||||
notification_msg = "Lesson Message: #{msg}"
|
||||
end
|
||||
return notification_msg
|
||||
|
||||
|
|
@ -404,7 +407,7 @@ module JamRuby
|
|||
end
|
||||
end
|
||||
|
||||
def send_lesson_message(purpose, lesson_session, student_directed)
|
||||
def send_lesson_message(purpose, lesson_session, student_directed, msg = nil)
|
||||
|
||||
notification = Notification.new
|
||||
notification.description = NotificationTypes::LESSON_MESSAGE
|
||||
|
|
@ -422,9 +425,11 @@ module JamRuby
|
|||
notification.session_id = lesson_session.music_session.id
|
||||
notification.lesson_session_id = lesson_session.id
|
||||
|
||||
notification_msg = format_msg(NotificationTypes::LESSON_MESSAGE, {purpose: purpose})
|
||||
notification_msg = format_msg(NotificationTypes::LESSON_MESSAGE, {purpose: purpose, msg: msg})
|
||||
|
||||
#notification.message = notification_msg
|
||||
if purpose == 'chat'
|
||||
notification.message = msg
|
||||
end
|
||||
|
||||
notification.save
|
||||
|
||||
|
|
@ -756,7 +761,7 @@ module JamRuby
|
|||
end
|
||||
|
||||
begin
|
||||
UserMailer.teacher_scheduled_jamclass_invitation(music_session.lesson_session.teacher, notification_msg, music_session).deliver
|
||||
#UserMailer.teacher_scheduled_jamclass_invitation(music_session.lesson_session.teacher, notification_msg, music_session).deliver
|
||||
rescue => e
|
||||
@@log.error("Unable to send SCHEDULED_JAMCLASS_INVITATION email to user #{music_session.lesson_session.teacher.email} #{e}")
|
||||
end
|
||||
|
|
@ -796,7 +801,7 @@ module JamRuby
|
|||
end
|
||||
|
||||
begin
|
||||
UserMailer.student_scheduled_jamclass_invitation(student, notification_msg, music_session).deliver
|
||||
#UserMailer.student_scheduled_jamclass_invitation(student, notification_msg, music_session).deliver
|
||||
rescue => e
|
||||
@@log.error("Unable to send SCHEDULED_JAMCLASS_INVITATION email to user #{student.email} #{e}")
|
||||
end
|
||||
|
|
@ -1094,7 +1099,7 @@ module JamRuby
|
|||
# start in less than 24 hours, and haven't been
|
||||
# notified for a particular interval yet:
|
||||
def send_session_reminders
|
||||
MusicSession.where("scheduled_start > NOW() AND scheduled_start <= (NOW()+INTERVAL '1 DAYS')").each do |candidate_session|
|
||||
MusicSession.where("scheduled_start > NOW() AND scheduled_start <= (NOW()+INTERVAL '1 DAYS') AND lesson_session_id IS NULL").each do |candidate_session|
|
||||
tm = candidate_session.scheduled_start
|
||||
if (tm>(12.hours.from_now) && !notified?(candidate_session, NotificationTypes::SCHEDULED_SESSION_REMINDER_DAY))
|
||||
# Send 24 hour reminders:
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ module JamRuby
|
|||
|
||||
belongs_to :sale
|
||||
belongs_to :recurly_transaction_web_hook
|
||||
belongs_to :charge
|
||||
|
||||
|
||||
def self.index(user, params = {})
|
||||
|
|
@ -14,7 +15,7 @@ module JamRuby
|
|||
limit = limit.to_i
|
||||
|
||||
query = PaymentHistory.limit(limit)
|
||||
.includes(sale: [:sale_line_items], recurly_transaction_web_hook:[])
|
||||
.includes(sale: [:sale_line_items], recurly_transaction_web_hook:[], charge:[])
|
||||
.where(user_id: user.id)
|
||||
.where("transaction_type = 'sale' OR transaction_type = 'refund' OR transaction_type = 'void'")
|
||||
.order('created_at DESC')
|
||||
|
|
|
|||
|
|
@ -208,8 +208,8 @@ module JamRuby
|
|||
free && non_free
|
||||
end
|
||||
|
||||
def self.purchase_test_drive(current_user, booking = nil)
|
||||
self.purchase_lesson(current_user, booking, LessonPackageType.test_drive)
|
||||
def self.purchase_test_drive(current_user, lesson_package_type, booking = nil)
|
||||
self.purchase_lesson(current_user, booking, lesson_package_type)
|
||||
end
|
||||
|
||||
def self.purchase_normal(current_user, booking)
|
||||
|
|
@ -273,6 +273,7 @@ module JamRuby
|
|||
purchase = LessonPackagePurchase.create(current_user, lesson_booking, lesson_package_type) if purchase.nil?
|
||||
|
||||
if purchase.errors.any?
|
||||
puts "purchase errors #{purchase.errors.inspect}"
|
||||
price_info = {}
|
||||
price_info[:purchase] = purchase
|
||||
return price_info
|
||||
|
|
|
|||
|
|
@ -43,14 +43,17 @@ module JamRuby
|
|||
JamTrack.find_by_id(product_id)
|
||||
elsif product_type == GIFTCARD
|
||||
GiftCardType.find_by_id(product_id)
|
||||
elsif product_type == LESSON
|
||||
lesson_package_purchase
|
||||
else
|
||||
|
||||
raise 'unsupported product type'
|
||||
end
|
||||
end
|
||||
|
||||
def product_info
|
||||
item = product
|
||||
{ name: product.name } if item
|
||||
{ name: product.name, product_type: product_type } if item
|
||||
end
|
||||
|
||||
def state
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ module JamRuby
|
|||
has_many :students, class_name: ::JamRuby::User
|
||||
has_many :teachers, class_name: ::JamRuby::Teacher
|
||||
has_many :school_invitations, class_name: 'JamRuby::SchoolInvitation'
|
||||
has_many :teacher_payments, class_name: 'JamRuby::TeacherPayment'
|
||||
has_many :teacher_distributions, class_name: 'JamRuby::TeacherDistribution'
|
||||
|
||||
validates :user, presence: true
|
||||
validates :enabled, inclusion: {in: [true, false]}
|
||||
|
|
|
|||
|
|
@ -44,10 +44,25 @@ module JamRuby
|
|||
SignupHint.where("created_at < :week", {:week => 1.week.ago}).delete_all
|
||||
end
|
||||
|
||||
def self.most_recent_redirect(user, default)
|
||||
def self.most_recent_redirect(user, default, queryParams=nil)
|
||||
puts "jquery params"
|
||||
hint = SignupHint.where(user_id: user.id).order('created_at desc').first
|
||||
|
||||
if hint
|
||||
hint.redirect_location
|
||||
redirect = hint.redirect_location
|
||||
puts "redirect #{redirect}"
|
||||
uri = URI.parse(redirect)
|
||||
bits = uri.query ? URI.decode_www_form(uri.query) : []
|
||||
if queryParams
|
||||
queryParams.each do |k, v|
|
||||
bits << [k, v]
|
||||
end
|
||||
end
|
||||
|
||||
puts "bits #{bits}"
|
||||
uri.query = URI.encode_www_form(bits)
|
||||
puts "oh yeah #{uri.to_s}"
|
||||
return uri.to_s
|
||||
else
|
||||
default
|
||||
end
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ module JamRuby
|
|||
|
||||
query = User.joins(:teacher)
|
||||
|
||||
# only show teachers with background check set and ready for session set to true
|
||||
# only show teachers with ready for session set to true
|
||||
query = query.where('teachers.ready_for_session_at IS NOT NULL')
|
||||
|
||||
instruments = params[:instruments]
|
||||
|
|
@ -145,7 +145,11 @@ module JamRuby
|
|||
|
||||
def self.save_teacher(user, params)
|
||||
teacher = build_teacher(user, params)
|
||||
teacher.save
|
||||
if teacher.save
|
||||
# flag the user as a teacher
|
||||
teacher.user.is_a_teacher = true
|
||||
teacher.user.save(validate: false)
|
||||
end
|
||||
teacher
|
||||
end
|
||||
|
||||
|
|
@ -190,8 +194,10 @@ module JamRuby
|
|||
teacher.price_per_month_120_cents = params[:price_per_month_120_cents] if params.key?(:price_per_month_120_cents)
|
||||
teacher.teaches_test_drive = params[:teaches_test_drive] if params.key?(:teaches_test_drive)
|
||||
teacher.test_drives_per_week = params[:test_drives_per_week] if params.key?(:test_drives_per_week)
|
||||
teacher.test_drives_per_week ||= 10 # default to 10 in absence of others
|
||||
teacher.school_id = params[:school_id] if params.key?(:school_id)
|
||||
|
||||
|
||||
# Many-to-many relations:
|
||||
if params.key?(:genres)
|
||||
genres = params[:genres]
|
||||
|
|
@ -317,7 +323,7 @@ module JamRuby
|
|||
end
|
||||
|
||||
def has_stripe_billing?
|
||||
false
|
||||
user.has_stripe_connect?
|
||||
end
|
||||
|
||||
def has_instruments_or_subject?
|
||||
|
|
|
|||
|
|
@ -5,10 +5,43 @@ module JamRuby
|
|||
belongs_to :teacher_payment, class_name: "JamRuby::TeacherPayment"
|
||||
belongs_to :lesson_session, class_name: "JamRuby::LessonSession"
|
||||
belongs_to :lesson_package_purchase, class_name: "JamRuby::LessonPackagePurchase"
|
||||
belongs_to :school, class_name: "JamRuby::School"
|
||||
|
||||
validates :teacher, presence: true
|
||||
validates :amount_in_cents, presence: true
|
||||
|
||||
def self.index(current_user, params)
|
||||
limit = params[:per_page]
|
||||
limit ||= 100
|
||||
limit = limit.to_i
|
||||
|
||||
query = TeacherDistribution.where(teacher_id: current_user.id).where('school_id IS NULL').order('created_at desc')
|
||||
|
||||
current_page = params[:page].nil? ? 1 : params[:page].to_i
|
||||
next_page = current_page + 1
|
||||
|
||||
# will_paginate gem
|
||||
query = query.paginate(:page => current_page, :per_page => limit)
|
||||
|
||||
if query.length == 0 # no more results
|
||||
{query: query, next_page: nil}
|
||||
elsif query.length < limit # no more results
|
||||
{query: query, next_page: nil}
|
||||
else
|
||||
{query: query, next_page: next_page}
|
||||
end
|
||||
end
|
||||
|
||||
def not_collectable
|
||||
if is_test_drive?
|
||||
false
|
||||
elsif is_normal?
|
||||
!lesson_session.billing_should_retry
|
||||
else
|
||||
! lesson_package_purchase.billing_should_retry
|
||||
end
|
||||
end
|
||||
|
||||
def self.create_for_lesson(lesson_session)
|
||||
distribution = create(lesson_session)
|
||||
distribution.lesson_session = lesson_session
|
||||
|
|
@ -26,13 +59,35 @@ module JamRuby
|
|||
distribution.teacher = target.teacher
|
||||
distribution.ready = false
|
||||
distribution.distributed = false
|
||||
distribution.amount_in_cents = target.lesson_booking.distribution_price_in_cents
|
||||
distribution.amount_in_cents = target.lesson_booking.distribution_price_in_cents(target)
|
||||
distribution.school = target.lesson_booking.school
|
||||
distribution
|
||||
end
|
||||
|
||||
def amount
|
||||
amount_in_cents / 100.0
|
||||
end
|
||||
|
||||
def real_distribution_in_cents
|
||||
amount_in_cents - calculate_teacher_fee
|
||||
end
|
||||
|
||||
def real_distribution
|
||||
(real_distribution_in_cents / 100.0)
|
||||
end
|
||||
|
||||
def real_distribution_display
|
||||
'$%.2f' % real_distribution
|
||||
end
|
||||
|
||||
def calculate_teacher_fee
|
||||
if is_test_drive?
|
||||
0
|
||||
else
|
||||
(amount_in_cents * (teacher.teacher.jamkazam_rate + 0.03)).round
|
||||
end
|
||||
end
|
||||
|
||||
def student
|
||||
if lesson_session
|
||||
lesson_session.student
|
||||
|
|
@ -59,17 +114,9 @@ module JamRuby
|
|||
|
||||
def description
|
||||
if lesson_session
|
||||
if lesson_session.lesson_booking.is_test_drive?
|
||||
"Test Drive session with #{lesson_session.lesson_booking.student.name} on #{lesson_session.scheduled_start.to_date}"
|
||||
elsif lesson_session.lesson_booking.is_normal?
|
||||
if lesson_session.lesson_booking.is_weekly_payment? || lesson_session.lesson_booking.is_monthly_payment?
|
||||
raise "Should not be here"
|
||||
else
|
||||
"A session with #{lesson_session.lesson_booking.student.name} on #{lesson_session.scheduled_start.to_date}"
|
||||
end
|
||||
end
|
||||
lesson_session.timed_description
|
||||
else
|
||||
"Monthly session for the month of #{lesson_package_purchase.month_name} with #{lesson_package_purchase.lesson_booking.student.name}"
|
||||
lesson_package_purchase.description
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -4,12 +4,22 @@ module JamRuby
|
|||
belongs_to :teacher, class_name: "JamRuby::User", foreign_key: :teacher_id
|
||||
belongs_to :teacher_payment_charge, class_name: "JamRuby::TeacherPaymentCharge", foreign_key: :charge_id
|
||||
has_one :teacher_distribution, class_name: "JamRuby::TeacherDistribution"
|
||||
belongs_to :school, class_name: "JamRuby::School"
|
||||
|
||||
|
||||
def self.hourly_check
|
||||
teacher_payments
|
||||
end
|
||||
|
||||
# pay the school if the payment owns the school; otherwise default to the teacher
|
||||
def payable_teacher
|
||||
if school
|
||||
school.owner
|
||||
else
|
||||
teacher
|
||||
end
|
||||
end
|
||||
|
||||
def teacher_distributions
|
||||
[teacher_distribution]
|
||||
end
|
||||
|
|
@ -51,15 +61,10 @@ module JamRuby
|
|||
24
|
||||
end
|
||||
|
||||
def calculate_teacher_fee
|
||||
if teacher_distribution.is_test_drive?
|
||||
0
|
||||
else
|
||||
(amount_in_cents * 0.28).round
|
||||
end
|
||||
def real_distribution_in_cents
|
||||
amount_in_cents - fee_in_cents
|
||||
end
|
||||
|
||||
|
||||
# will find, for a given teacher, an outstading unsuccessful payment or make a new one.
|
||||
# it will then associate a charge with it, and then execute the charge.
|
||||
def self.charge(teacher)
|
||||
|
|
@ -79,12 +84,13 @@ module JamRuby
|
|||
payment.teacher_distribution = teacher_distribution
|
||||
end
|
||||
|
||||
|
||||
payment.school = payment.teacher_distribution.school
|
||||
payment.amount_in_cents = payment.teacher_distribution.amount_in_cents
|
||||
payment.fee_in_cents = payment.calculate_teacher_fee
|
||||
payment.fee_in_cents = payment.teacher_distribution.calculate_teacher_fee
|
||||
|
||||
if payment.teacher_payment_charge.nil?
|
||||
charge = TeacherPaymentCharge.new
|
||||
charge.user = payment.payable_teacher
|
||||
charge.amount_in_cents = payment.amount_in_cents
|
||||
charge.fee_in_cents = payment.fee_in_cents
|
||||
charge.teacher_payment = payment
|
||||
|
|
|
|||
|
|
@ -12,15 +12,13 @@ module JamRuby
|
|||
end
|
||||
|
||||
def teacher
|
||||
@teacher ||= teacher_payment.teacher
|
||||
@teacher ||= teacher_payment.payable_teacher
|
||||
end
|
||||
|
||||
def charged_user
|
||||
teacher
|
||||
end
|
||||
|
||||
|
||||
|
||||
def do_charge(force)
|
||||
|
||||
# source will let you supply a token. But... how to get a token in this case?
|
||||
|
|
@ -38,11 +36,17 @@ module JamRuby
|
|||
end
|
||||
|
||||
def do_send_notices
|
||||
UserMailer.teacher_distribution_done(teacher_payment)
|
||||
unless teacher_payment.school && distribution.is_monthly?
|
||||
# we don't send monthly success notices to the teacher if they are in a school, otherwise they get an email
|
||||
UserMailer.teacher_distribution_done(teacher_payment).deliver
|
||||
end
|
||||
if teacher_payment.school
|
||||
UserMailer.school_distribution_done(teacher_payment).deliver
|
||||
end
|
||||
end
|
||||
|
||||
def do_send_unable_charge
|
||||
UserMailer.teacher_distribution_fail(teacher_payment)
|
||||
UserMailer.teacher_distribution_fail(teacher_payment).deliver
|
||||
end
|
||||
|
||||
def construct_description
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ module JamRuby
|
|||
has_many :user_authorizations, :class_name => "JamRuby::UserAuthorization"
|
||||
|
||||
has_many :reviews, :class_name => "JamRuby::Review"
|
||||
has_one :review_summary, :class_name => "JamRuby::ReviewSummary"
|
||||
has_one :review_summary, :class_name => "JamRuby::ReviewSummary"
|
||||
|
||||
# calendars (for scheduling NOT in music_session)
|
||||
has_many :calendars, :class_name => "JamRuby::Calendar"
|
||||
|
|
@ -71,7 +71,7 @@ module JamRuby
|
|||
has_many :band_musicians, :class_name => "JamRuby::BandMusician"
|
||||
has_many :bands, :through => :band_musicians, :class_name => "JamRuby::Band"
|
||||
has_one :teacher, :class_name => "JamRuby::Teacher"
|
||||
|
||||
|
||||
# genres
|
||||
has_many :genre_players, as: :player, class_name: "JamRuby::GenrePlayer", dependent: :destroy
|
||||
has_many :genres, through: :genre_players, class_name: "JamRuby::Genre"
|
||||
|
|
@ -101,7 +101,7 @@ module JamRuby
|
|||
has_many :followers, :as => :followable, :class_name => "JamRuby::Follow", :dependent => :destroy
|
||||
|
||||
# text messages
|
||||
has_many :text_messages, :class_name => "JamRuby:TextMessage", :foreign_key => "target_user_id"
|
||||
has_many :text_messages, :class_name => "JamRuby::TextMessage", :foreign_key => "target_user_id"
|
||||
|
||||
# notifications
|
||||
has_many :notifications, :class_name => "JamRuby::Notification", :foreign_key => "target_user_id"
|
||||
|
|
@ -176,6 +176,7 @@ module JamRuby
|
|||
has_many :teacher_lesson_bookings, :class_name => "JamRuby::LessonBooking", :foreign_key => "teacher_id", inverse_of: :teacher
|
||||
has_many :teacher_distributions, :class_name => "JamRuby::TeacherDistribution", :foreign_key => "teacher_id", inverse_of: :teacher
|
||||
has_many :teacher_payments, :class_name => "JamRuby::TeacherPayment", :foreign_key => "teacher_id", inverse_of: :teacher
|
||||
belongs_to :desired_package, :class_name => "JamRuby::LessonPackageType", :foreign_key => "lesson_package_type_id", inverse_of: :user_desired_packages # used to hold whether user last wanted test drive 4/2/1
|
||||
|
||||
# Shopping carts
|
||||
has_many :shopping_carts, :class_name => "JamRuby::ShoppingCart"
|
||||
|
|
@ -209,6 +210,8 @@ module JamRuby
|
|||
before_save :create_remember_token, :if => :should_validate_password?
|
||||
before_save :stringify_avatar_info, :if => :updating_avatar
|
||||
|
||||
after_save :after_save
|
||||
|
||||
validates :first_name, length: {maximum: 50}, no_profanity: true
|
||||
validates :last_name, length: {maximum: 50}, no_profanity: true
|
||||
validates :biography, length: {maximum: 4000}, no_profanity: true
|
||||
|
|
@ -255,11 +258,22 @@ module JamRuby
|
|||
scope :musicians_geocoded, musicians.geocoded_users
|
||||
scope :email_opt_in, where(:subscribe_email => true)
|
||||
|
||||
def after_save
|
||||
if school_interest && !school_interest_was
|
||||
AdminMailer.partner({body: "#{email} signed up via the https://www.jamkazam.com/landing/jamclass/schools page.\n\nFull list is here: https://www.jamkazam.com/admin/admin/school_interests", subject: "#{email} is interested in schools"}).deliver
|
||||
if owned_school.nil?
|
||||
school = School.new
|
||||
school.user = self
|
||||
school.save!
|
||||
end
|
||||
end
|
||||
end
|
||||
def update_teacher_pct
|
||||
if teacher
|
||||
teacher.update_profile_pct
|
||||
end
|
||||
end
|
||||
|
||||
def user_progression_fields
|
||||
@user_progression_fields ||= Set.new ["first_downloaded_client_at", "first_ran_client_at", "first_music_session_at", "first_real_music_session_at", "first_good_music_session_at", "first_certified_gear_at", "first_invited_at", "first_friended_at", "first_recording_at", "first_social_promoted_at", "first_played_jamtrack_at"]
|
||||
end
|
||||
|
|
@ -1090,6 +1104,7 @@ module JamRuby
|
|||
teacher = options[:teacher]
|
||||
school_invitation_code = options[:school_invitation_code]
|
||||
school_id = options[:school_id]
|
||||
school_interest = options[:school_interest]
|
||||
|
||||
user = User.new
|
||||
user.validate_instruments = true
|
||||
|
|
@ -1115,6 +1130,7 @@ module JamRuby
|
|||
user.has_redeemable_jamtrack = true
|
||||
user.is_a_student = !!student
|
||||
user.is_a_teacher = !!teacher
|
||||
user.school_interest = !!school_interest
|
||||
if user.is_a_student || user.is_a_teacher
|
||||
musician = true
|
||||
end
|
||||
|
|
@ -1125,7 +1141,7 @@ module JamRuby
|
|||
user.school_id = school_id
|
||||
elsif user.is_a_teacher
|
||||
school = School.find_by_id(school_id)
|
||||
school_name = school ? school.name : 'a music school'
|
||||
school_name = school ? school.name : 'a music school'
|
||||
user.teacher = Teacher.build_teacher(user, validate_introduction: true, biography: "Teaches for #{school_name}", school_id: school_id)
|
||||
end
|
||||
else
|
||||
|
|
@ -1318,16 +1334,13 @@ module JamRuby
|
|||
end if affiliate_referral_id.present?
|
||||
|
||||
|
||||
|
||||
if user.is_a_student
|
||||
UserMailer.student_welcome_message(user).deliver
|
||||
end
|
||||
|
||||
if user.is_a_teacher
|
||||
elsif user.is_a_teacher
|
||||
UserMailer.teacher_welcome_message(user).deliver
|
||||
end
|
||||
|
||||
if !user.is_a_teacher && !user.is_a_student
|
||||
elsif user.school_interest
|
||||
UserMailer.school_owner_welcome_message(user).deliver
|
||||
else
|
||||
UserMailer.welcome_message(user).deliver
|
||||
end
|
||||
|
||||
|
|
@ -1891,7 +1904,7 @@ module JamRuby
|
|||
end
|
||||
|
||||
def can_buy_test_drive?
|
||||
lesson_purchases.where(lesson_package_type_id: LessonPackageType.test_drive.id).where('created_at > ?', APP_CONFIG.test_drive_wait_period_year.years.ago).count == 0
|
||||
lesson_purchases.where('lesson_package_type_id in (?)', LessonPackageType.test_drive_package_ids).where('created_at > ?', APP_CONFIG.test_drive_wait_period_year.years.ago).count == 0
|
||||
end
|
||||
|
||||
def has_test_drives?
|
||||
|
|
@ -1906,6 +1919,15 @@ module JamRuby
|
|||
!requested_test_drive(teacher).nil?
|
||||
end
|
||||
|
||||
def stripe_auth
|
||||
user_authorizations.where(provider: "stripe_connect").first
|
||||
end
|
||||
|
||||
def has_stripe_connect?
|
||||
auth = stripe_auth
|
||||
auth && (!auth.token_expiration || auth.token_expiration > Time.now)
|
||||
end
|
||||
|
||||
def fetch_stripe_customer
|
||||
Stripe::Customer.retrieve(stripe_customer_id)
|
||||
end
|
||||
|
|
@ -1931,9 +1953,11 @@ module JamRuby
|
|||
|
||||
customer
|
||||
end
|
||||
def card_approved(token, zip)
|
||||
|
||||
def card_approved(token, zip, booking_id)
|
||||
|
||||
approved_booking = nil
|
||||
found_uncollectables = nil
|
||||
User.transaction do
|
||||
self.stripe_token = token if token
|
||||
self.stripe_zip_code = zip if zip
|
||||
|
|
@ -1941,14 +1965,22 @@ module JamRuby
|
|||
self.stripe_customer_id = customer.id
|
||||
self.stored_credit_card = true
|
||||
if self.save
|
||||
# we can also 'unlock' any booked sessions that still need to be done so
|
||||
LessonBooking.unprocessed(self).each do |booking|
|
||||
booking.card_approved
|
||||
approved_booking = booking
|
||||
if booking_id
|
||||
approved_booking = LessonBooking.find_by_id(booking_id)
|
||||
if approved_booking
|
||||
approved_booking.card_approved
|
||||
end
|
||||
end
|
||||
|
||||
if uncollectables.count > 0
|
||||
found_uncollectables = uncollectables
|
||||
uncollectables.update_all(billing_should_retry: true)
|
||||
else
|
||||
found_uncollectables = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
approved_booking
|
||||
[approved_booking, found_uncollectables]
|
||||
end
|
||||
|
||||
def update_name(name)
|
||||
|
|
@ -1977,6 +2009,8 @@ module JamRuby
|
|||
normal = nil
|
||||
intent = nil
|
||||
purchase = nil
|
||||
lesson_package_type = nil
|
||||
uncollectables = nil
|
||||
User.transaction do
|
||||
|
||||
if params[:name].present?
|
||||
|
|
@ -1985,20 +2019,32 @@ module JamRuby
|
|||
end
|
||||
end
|
||||
|
||||
booking = card_approved(params[:token], params[:zip])
|
||||
booking, uncollectables = card_approved(params[:token], params[:zip], params[:booking_id])
|
||||
if params[:test_drive]
|
||||
self.reload
|
||||
result = Sale.purchase_test_drive(self, booking)
|
||||
if booking
|
||||
lesson_package_type = booking.resolved_test_drive_package
|
||||
end
|
||||
if lesson_package_type.nil?
|
||||
lesson_package_type = LessonPackageType.test_drive_4
|
||||
end
|
||||
|
||||
|
||||
result = Sale.purchase_test_drive(self, lesson_package_type, booking)
|
||||
test_drive = result[:sale]
|
||||
purchase = result[:purchase]
|
||||
|
||||
if booking && !purchase.errors.any?
|
||||
# the booking would not have a lesson_package_purchase associated yet, so let's associate it
|
||||
booking.lesson_sessions.update_all(lesson_package_purchase_id: purchase.id)
|
||||
end
|
||||
elsif params[:normal]
|
||||
self.reload
|
||||
end
|
||||
|
||||
intent = TeacherIntent.recent_test_drive(self)
|
||||
end
|
||||
|
||||
{lesson: booking, test_drive: test_drive, intent:intent, purchase: purchase}
|
||||
{lesson: booking, test_drive: test_drive, purchase: purchase, lesson_package_type: lesson_package_type, uncollectables: uncollectables}
|
||||
end
|
||||
|
||||
def requested_test_drive(teacher = nil)
|
||||
|
|
@ -2018,7 +2064,16 @@ module JamRuby
|
|||
end
|
||||
|
||||
def most_recent_test_drive_purchase
|
||||
lesson_purchases.where(lesson_package_type_id: LessonPackageType.test_drive.id).order('created_at desc').first
|
||||
lesson_purchases.where('lesson_package_type_id in (?)', [LessonPackageType.test_drive_package_ids]).order('created_at desc').first
|
||||
end
|
||||
|
||||
def total_test_drives
|
||||
purchase = most_recent_test_drive_purchase
|
||||
if purchase
|
||||
purchase.test_drive_count
|
||||
else
|
||||
0
|
||||
end
|
||||
end
|
||||
|
||||
def test_drive_succeeded(lesson_session)
|
||||
|
|
@ -2031,16 +2086,26 @@ module JamRuby
|
|||
end
|
||||
end
|
||||
|
||||
def test_drive_declined(lesson_session)
|
||||
# because we decrement test_drive credits as soon as you book, we need to bring it back now
|
||||
self.remaining_test_drives = self.remaining_test_drives + 1
|
||||
self.save(validate: false)
|
||||
end
|
||||
|
||||
def test_drive_failed(lesson_session)
|
||||
# because we decrement test_drive credits as soon as you book, we need to bring it back now
|
||||
self.remaining_test_drives = self.remaining_test_drives + 1
|
||||
self.save(validate: false)
|
||||
|
||||
UserMailer.test_drive_no_bill(self, lesson_session).deliver
|
||||
UserMailer.student_test_drive_no_bill(lesson_session).deliver
|
||||
end
|
||||
|
||||
def used_test_drives
|
||||
4 - remaining_test_drives
|
||||
total_test_drives - remaining_test_drives
|
||||
end
|
||||
|
||||
def uncollectables(limit = 10)
|
||||
LessonPaymentCharge.where(user_id:self.id).order(:created_at).where('billing_attempts > 0').where(billed: false).limit(limit)
|
||||
end
|
||||
|
||||
def has_rated_teacher(teacher)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
module JamRuby
|
||||
class MinutelyJob
|
||||
extend Resque::Plugins::JamLonelyJob
|
||||
|
||||
@queue = :scheduled_minutely_job
|
||||
@@log = Logging.logger[MinutelyJob]
|
||||
|
||||
def self.perform
|
||||
@@log.debug("waking up")
|
||||
|
||||
LessonSession.minutely_check
|
||||
|
||||
@@log.debug("done")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -980,7 +980,7 @@ FactoryGirl.define do
|
|||
price 30.00
|
||||
|
||||
factory :test_drive_purchase do
|
||||
lesson_package_type { JamRuby::LessonPackageType.test_drive }
|
||||
lesson_package_type { JamRuby::LessonPackageType.test_drive_4 }
|
||||
association :lesson_booking, factory: :lesson_booking
|
||||
price 49.99
|
||||
end
|
||||
|
|
@ -1010,6 +1010,13 @@ FactoryGirl.define do
|
|||
|
||||
factory :teacher_payment_charge, parent: :charge, class: 'JamRuby::TeacherPaymentCharge' do
|
||||
type 'JamRuby::TeacherPaymentCharge'
|
||||
association :user, factory: :user
|
||||
end
|
||||
|
||||
|
||||
factory :lesson_payment_charge, parent: :charge, class: 'JamRuby::LessonPaymentCharge' do
|
||||
type 'JamRuby::LessonPaymentCharge'
|
||||
association :user, factory: :user
|
||||
end
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -38,11 +38,11 @@ describe "Monthly Recurring Lesson Flow" do
|
|||
########## Need validate their credit card
|
||||
token = create_stripe_token
|
||||
result = user.payment_update({token: token, zip: '78759', normal: true})
|
||||
booking = result[:lesson]
|
||||
lesson = booking.lesson_sessions[0]
|
||||
booking.card_presumed_ok.should be_true
|
||||
booking.errors.any?.should be_false
|
||||
lesson.errors.any?.should be_false
|
||||
booking.card_presumed_ok.should be_true
|
||||
booking = result[:lesson]
|
||||
lesson = booking.lesson_sessions[0]
|
||||
booking.sent_notices.should be_true
|
||||
lesson.music_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)
|
||||
lesson.amount_charged.should be 0.0
|
||||
|
|
@ -116,7 +116,7 @@ describe "Monthly Recurring Lesson Flow" do
|
|||
# puts del.inspect
|
||||
end
|
||||
# get acceptance emails, as well as 'your stuff is accepted'
|
||||
UserMailer.deliveries.length.should eql 6
|
||||
UserMailer.deliveries.length.should eql 2
|
||||
lesson_session.errors.any?.should be_false
|
||||
lesson_session.reload
|
||||
lesson_session.slot.should eql student_counter
|
||||
|
|
@ -126,9 +126,10 @@ describe "Monthly Recurring Lesson Flow" do
|
|||
lesson_session.music_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)
|
||||
booking.status.should eql LessonBooking::STATUS_APPROVED
|
||||
|
||||
UserMailer.deliveries.length.should eql 6
|
||||
UserMailer.deliveries.length.should eql 2
|
||||
chat = ChatMessage.unscoped.order(:created_at).last
|
||||
chat.message.should eql "Lesson Approved: 'Yeah I got this'"
|
||||
chat.message.should eql 'Yeah I got this'
|
||||
chat.purpose.should eql 'Lesson Approved'
|
||||
chat.channel.should eql ChatMessage::CHANNEL_LESSON
|
||||
chat.user.should eql teacher_user
|
||||
chat.target_user.should eql user
|
||||
|
|
@ -185,7 +186,7 @@ describe "Monthly Recurring Lesson Flow" do
|
|||
lesson_purchase.sale_line_item.should eql line_item
|
||||
|
||||
TeacherPayment.count.should eql 0
|
||||
TeacherPayment.daily_check
|
||||
TeacherPayment.hourly_check
|
||||
teacher_distribution.reload
|
||||
teacher_distribution.distributed.should be_true
|
||||
TeacherPayment.count.should eql 1
|
||||
|
|
|
|||
|
|
@ -12,9 +12,12 @@ describe "Normal Lesson Flow" do
|
|||
let(:lesson_booking_slot_recurring2) { FactoryGirl.build(:lesson_booking_slot_recurring) }
|
||||
let(:valid_single_slots) { [lesson_booking_slot_single1, lesson_booking_slot_single2] }
|
||||
let(:valid_recurring_slots) { [lesson_booking_slot_recurring1, lesson_booking_slot_recurring2] }
|
||||
let(:school) {FactoryGirl.create(:school)}
|
||||
|
||||
describe "stripe mocked" do
|
||||
before { StripeMock.start
|
||||
before {
|
||||
StripeMock.clear_errors
|
||||
StripeMock.start
|
||||
teacher.stripe_account_id = stripe_account1_id
|
||||
teacher.save!
|
||||
}
|
||||
|
|
@ -35,7 +38,7 @@ describe "Normal Lesson Flow" do
|
|||
|
||||
########## Need validate their credit card
|
||||
token = create_stripe_token
|
||||
result = user.payment_update({token: token, zip: '78759', normal: true})
|
||||
result = user.payment_update({token: token, zip: '78759', normal: true, booking_id: booking.id})
|
||||
booking = result[:lesson]
|
||||
lesson = booking.lesson_sessions[0]
|
||||
booking.errors.any?.should be_false
|
||||
|
|
@ -71,9 +74,10 @@ describe "Normal Lesson Flow" do
|
|||
lesson_session.music_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)
|
||||
booking.status.should eql LessonBooking::STATUS_APPROVED
|
||||
|
||||
UserMailer.deliveries.length.should eql 4
|
||||
UserMailer.deliveries.length.should eql 2
|
||||
chat = ChatMessage.unscoped.order(:created_at).last
|
||||
chat.message.should eql "Lesson Approved: 'Yeah I got this'"
|
||||
chat.message.should eql 'Yeah I got this'
|
||||
chat.purpose.should eql 'Lesson Approved'
|
||||
chat.channel.should eql ChatMessage::CHANNEL_LESSON
|
||||
chat.user.should eql teacher_user
|
||||
chat.target_user.should eql user
|
||||
|
|
@ -91,6 +95,7 @@ describe "Normal Lesson Flow" do
|
|||
lesson_session.music_session.session_removed_at = end_time
|
||||
lesson_session.music_session.save!
|
||||
|
||||
Timecop.travel(end_time + 1)
|
||||
|
||||
UserMailer.deliveries.clear
|
||||
# background code comes around and analyses the session
|
||||
|
|
@ -177,12 +182,12 @@ describe "Normal Lesson Flow" do
|
|||
|
||||
lesson_session.reload
|
||||
payment = lesson_session.lesson_payment_charge
|
||||
|
||||
payment.amount_in_cents.should eql 3248
|
||||
payment.fee_in_cents.should eql 0
|
||||
|
||||
lesson_session.billing_attempts.should eql 4
|
||||
lesson_session.post_processed.should be_true
|
||||
LessonPaymentCharge.count.should eql 2
|
||||
LessonPaymentCharge.count.should eql 1
|
||||
|
||||
lesson_session.reload
|
||||
lesson_session.analysed.should be_true
|
||||
|
|
@ -266,7 +271,7 @@ describe "Normal Lesson Flow" do
|
|||
|
||||
########## Need validate their credit card
|
||||
token = create_stripe_token
|
||||
result = user.payment_update({token: token, zip: '78759', normal: true})
|
||||
result = user.payment_update({token: token, zip: '78759', normal: true, booking_id: booking.id})
|
||||
booking = result[:lesson]
|
||||
lesson = booking.lesson_sessions[0]
|
||||
booking.errors.any?.should be_false
|
||||
|
|
@ -351,9 +356,10 @@ describe "Normal Lesson Flow" do
|
|||
lesson_session.music_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)
|
||||
booking.status.should eql LessonBooking::STATUS_APPROVED
|
||||
|
||||
UserMailer.deliveries.length.should eql 4
|
||||
UserMailer.deliveries.length.should eql 2
|
||||
chat = ChatMessage.unscoped.order(:created_at).last
|
||||
chat.message.should eql "Lesson Approved: 'Yeah I got this'"
|
||||
chat.message.should eql 'Yeah I got this'
|
||||
chat.purpose.should eql 'Lesson Approved'
|
||||
chat.channel.should eql ChatMessage::CHANNEL_LESSON
|
||||
chat.user.should eql teacher_user
|
||||
chat.target_user.should eql user
|
||||
|
|
@ -371,6 +377,7 @@ describe "Normal Lesson Flow" do
|
|||
lesson_session.music_session.session_removed_at = end_time
|
||||
lesson_session.music_session.save!
|
||||
|
||||
Timecop.travel(end_time + 1)
|
||||
|
||||
UserMailer.deliveries.clear
|
||||
# background code comes around and analyses the session
|
||||
|
|
@ -411,4 +418,167 @@ describe "Normal Lesson Flow" do
|
|||
user.remaining_test_drives.should eql 0
|
||||
UserMailer.deliveries.length.should eql 2 # one for student, one for teacher
|
||||
end
|
||||
|
||||
|
||||
it "works (school on school)" do
|
||||
|
||||
# get user and teacher into same school
|
||||
user.school = school
|
||||
user.save!
|
||||
teacher.school = school
|
||||
teacher.save!
|
||||
|
||||
# user has no test drives, no credit card on file, but attempts to book a lesson
|
||||
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.school.should be_true
|
||||
booking.card_presumed_ok.should be_false
|
||||
booking.user.should eql user
|
||||
user.unprocessed_normal_lesson.should eql []
|
||||
booking.sent_notices.should be_false
|
||||
booking.booked_price.should eql 30.00
|
||||
booking.is_requested?.should be_true
|
||||
booking.sent_notices.should be_true
|
||||
lesson.music_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)
|
||||
LessonPaymentCharge.count.should eql 0
|
||||
|
||||
user.reload
|
||||
user.stripe_customer_id.should_not be nil
|
||||
user.remaining_test_drives.should eql 0
|
||||
user.lesson_purchases.length.should eql 0
|
||||
|
||||
customer = Stripe::Customer.retrieve(user.stripe_customer_id)
|
||||
customer.email.should eql user.email
|
||||
|
||||
booking.lesson_sessions.length.should eql 1
|
||||
lesson_session = booking.lesson_sessions[0]
|
||||
lesson_session.status.should eql LessonBooking::STATUS_REQUESTED
|
||||
booking.status.should eql LessonBooking::STATUS_REQUESTED
|
||||
|
||||
######### Teacher counters with new slot
|
||||
teacher_countered_slot = FactoryGirl.build(:lesson_booking_slot_single, hour: 14)
|
||||
UserMailer.deliveries.clear
|
||||
lesson_session.counter({proposer: teacher_user, slot: teacher_countered_slot, message: 'Does this work?'})
|
||||
booking.reload
|
||||
booking.errors.any?.should be false
|
||||
lesson_session.lesson_booking.errors.any?.should be false
|
||||
lesson_session.lesson_booking_slots.length.should eql 1
|
||||
lesson_session.lesson_booking_slots[0].proposer.should eql teacher_user
|
||||
teacher_counter = lesson_session.lesson_booking_slots.order(:created_at).last
|
||||
teacher_counter.should eql teacher_countered_slot
|
||||
teacher_counter.proposer.should eql teacher_user
|
||||
booking.lesson_booking_slots.length.should eql 3
|
||||
UserMailer.deliveries.length.should eql 1
|
||||
chat = ChatMessage.unscoped.order(:created_at).last
|
||||
chat.channel.should eql ChatMessage::CHANNEL_LESSON
|
||||
chat.message.should eql 'Does this work?'
|
||||
chat.user.should eql teacher_user
|
||||
chat.target_user.should eql user
|
||||
notification = Notification.unscoped.order(:created_at).last
|
||||
notification.session_id.should eql lesson_session.music_session.id
|
||||
notification.student_directed.should eql true
|
||||
notification.purpose.should eql 'counter'
|
||||
notification.description.should eql NotificationTypes::LESSON_MESSAGE
|
||||
|
||||
######### Student counters with new slot
|
||||
student_countered_slot = FactoryGirl.build(:lesson_booking_slot_single, hour: 16)
|
||||
UserMailer.deliveries.clear
|
||||
lesson_session.counter({proposer: user, slot: student_countered_slot, message: 'Does this work better?'})
|
||||
lesson_session.errors.any?.should be false
|
||||
lesson_session.lesson_booking.errors.any?.should be false
|
||||
lesson_session.lesson_booking_slots.length.should eql 2
|
||||
student_counter = booking.lesson_booking_slots.order(:created_at).last
|
||||
student_counter.proposer.should eql user
|
||||
booking.reload
|
||||
booking.lesson_booking_slots.length.should eql 4
|
||||
UserMailer.deliveries.length.should eql 1
|
||||
chat = ChatMessage.unscoped.order(:created_at).last
|
||||
chat.message.should eql 'Does this work better?'
|
||||
chat.channel.should eql ChatMessage::CHANNEL_LESSON
|
||||
chat.user.should eql user
|
||||
chat.target_user.should eql teacher_user
|
||||
notification = Notification.unscoped.order(:created_at).last
|
||||
notification.session_id.should eql lesson_session.music_session.id
|
||||
notification.student_directed.should eql false
|
||||
notification.purpose.should eql 'counter'
|
||||
notification.description.should eql NotificationTypes::LESSON_MESSAGE
|
||||
|
||||
######## Teacher accepts slot
|
||||
UserMailer.deliveries.clear
|
||||
|
||||
lesson_session.accept({message: 'Yeah I got this', slot: student_counter.id, update_all: false})
|
||||
lesson_session.errors.any?.should be_false
|
||||
lesson_session.reload
|
||||
lesson_session.slot.should eql student_counter
|
||||
lesson_session.status.should eql LessonSession::STATUS_APPROVED
|
||||
booking.reload
|
||||
booking.default_slot.should eql student_counter
|
||||
lesson_session.music_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)
|
||||
booking.status.should eql LessonBooking::STATUS_APPROVED
|
||||
|
||||
UserMailer.deliveries.length.should eql 2
|
||||
chat = ChatMessage.unscoped.order(:created_at).last
|
||||
chat.message.should eql 'Yeah I got this'
|
||||
chat.purpose.should eql 'Lesson Approved'
|
||||
chat.channel.should eql ChatMessage::CHANNEL_LESSON
|
||||
chat.user.should eql teacher_user
|
||||
chat.target_user.should eql user
|
||||
notification = Notification.unscoped.order(:created_at).last
|
||||
notification.session_id.should eql lesson_session.music_session.id
|
||||
notification.student_directed.should eql true
|
||||
notification.purpose.should eql 'accept'
|
||||
notification.description.should eql NotificationTypes::LESSON_MESSAGE
|
||||
|
||||
# teacher & student get into session
|
||||
start = lesson_session.scheduled_start
|
||||
end_time = lesson_session.scheduled_start + (60 * lesson_session.duration)
|
||||
uh2 = FactoryGirl.create(:music_session_user_history, user: teacher_user, history: lesson_session.music_session, created_at: start, session_removed_at: end_time)
|
||||
# artificially end the session, which is covered by other background jobs
|
||||
lesson_session.music_session.session_removed_at = end_time
|
||||
lesson_session.music_session.save!
|
||||
|
||||
Timecop.travel(end_time + 1)
|
||||
|
||||
UserMailer.deliveries.clear
|
||||
# background code comes around and analyses the session
|
||||
LessonSession.hourly_check
|
||||
lesson_session.reload
|
||||
lesson_session.analysed.should be_true
|
||||
analysis = JSON.parse(lesson_session.analysis)
|
||||
analysis["reason"].should eql LessonSessionAnalyser::STUDENT_FAULT
|
||||
analysis["student"].should eql LessonSessionAnalyser::NO_SHOW
|
||||
if lesson_session.billing_error_detail
|
||||
puts "testdrive flow #{lesson_session.billing_error_detail}" # this should not occur, but helps a great deal if a regression occurs and running all the tests
|
||||
end
|
||||
lesson_session.billed.should be true
|
||||
user.reload
|
||||
user.lesson_purchases.length.should eql 1
|
||||
lesson_purchase = user.lesson_purchases[0]
|
||||
lesson_purchase.price.should eql 30.00
|
||||
lesson_purchase.lesson_package_type.is_normal?.should eql true
|
||||
lesson_purchase.price_in_cents.should eql 3000
|
||||
user.sales.length.should eql 1
|
||||
sale = user.sales.first
|
||||
sale.stripe_charge_id.should_not be_nil
|
||||
sale.recurly_tax_in_cents.should eql (100 * booking.booked_price.to_f * 0.0825).round.to_i
|
||||
sale.recurly_total_in_cents.should eql ((100 * booking.booked_price.to_f * 0.0825).round + 100 * booking.booked_price.to_f).to_i
|
||||
sale.recurly_subtotal_in_cents.should eql (100 * booking.booked_price).to_i
|
||||
sale.recurly_currency.should eql 'USD'
|
||||
sale.stripe_charge_id.should_not be_nil
|
||||
line_item = sale.sale_line_items[0]
|
||||
line_item.quantity.should eql 1
|
||||
line_item.product_type.should eql SaleLineItem::LESSON
|
||||
line_item.product_id.should eq LessonPackageType.single.id
|
||||
line_item.lesson_package_purchase.should eql lesson_purchase
|
||||
lesson_purchase.sale_line_item.should eql line_item
|
||||
lesson.amount_charged.should eql (sale.recurly_total_in_cents / 100.0).to_f
|
||||
lesson_session.billing_error_reason.should be_nil
|
||||
lesson_session.sent_billing_notices.should be true
|
||||
user.reload
|
||||
user.remaining_test_drives.should eql 0
|
||||
UserMailer.deliveries.length.should eql 2 # one for student, one for teacher
|
||||
|
||||
LessonPaymentCharge.count.should eql 0
|
||||
TeacherDistribution.count.should eql 0
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -13,6 +13,9 @@ describe "Recurring Lesson Flow" do
|
|||
let(:valid_single_slots) { [lesson_booking_slot_single1, lesson_booking_slot_single2] }
|
||||
let(:valid_recurring_slots) { [lesson_booking_slot_recurring1, lesson_booking_slot_recurring2] }
|
||||
|
||||
before(:each) do
|
||||
Timecop.return
|
||||
end
|
||||
it "works" do
|
||||
|
||||
# user has no test drives, no credit card on file, but attempts to book a lesson
|
||||
|
|
@ -27,7 +30,7 @@ describe "Recurring Lesson Flow" do
|
|||
|
||||
########## Need validate their credit card
|
||||
token = create_stripe_token
|
||||
result = user.payment_update({token: token, zip: '78759', normal: true})
|
||||
result = user.payment_update({token: token, zip: '78759', normal: true, booking_id: booking.id})
|
||||
booking = result[:lesson]
|
||||
lesson = booking.lesson_sessions[0]
|
||||
booking.errors.any?.should be_false
|
||||
|
|
@ -107,7 +110,7 @@ describe "Recurring Lesson Flow" do
|
|||
# puts del.inspect
|
||||
end
|
||||
# get acceptance emails, as well as 'your stuff is accepted'
|
||||
UserMailer.deliveries.length.should eql 6
|
||||
UserMailer.deliveries.length.should eql 2
|
||||
lesson_session.errors.any?.should be_false
|
||||
lesson_session.reload
|
||||
lesson_session.slot.should eql student_counter
|
||||
|
|
@ -117,9 +120,10 @@ describe "Recurring Lesson Flow" do
|
|||
lesson_session.music_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)
|
||||
booking.status.should eql LessonBooking::STATUS_APPROVED
|
||||
|
||||
UserMailer.deliveries.length.should eql 6
|
||||
UserMailer.deliveries.length.should eql 2
|
||||
chat = ChatMessage.unscoped.order(:created_at).last
|
||||
chat.message.should eql "Lesson Approved: 'Yeah I got this'"
|
||||
chat.message.should eql "Yeah I got this"
|
||||
chat.purpose.should eql 'Lesson Approved'
|
||||
chat.channel.should eql ChatMessage::CHANNEL_LESSON
|
||||
chat.user.should eql teacher_user
|
||||
chat.target_user.should eql user
|
||||
|
|
@ -138,6 +142,7 @@ describe "Recurring Lesson Flow" do
|
|||
lesson_session.music_session.session_removed_at = end_time
|
||||
lesson_session.music_session.save!
|
||||
|
||||
Timecop.travel(end_time + 1)
|
||||
|
||||
UserMailer.deliveries.clear
|
||||
# background code comes around and analyses the session
|
||||
|
|
|
|||
|
|
@ -14,12 +14,16 @@ describe "TestDrive Lesson Flow" do
|
|||
let(:valid_recurring_slots) { [lesson_booking_slot_recurring1, lesson_booking_slot_recurring2] }
|
||||
|
||||
before {
|
||||
Timecop.return
|
||||
teacher.stripe_account_id = stripe_account1_id
|
||||
teacher.save!
|
||||
}
|
||||
|
||||
it "works" do
|
||||
|
||||
user.desired_package = LessonPackageType.test_drive_2
|
||||
user.save!
|
||||
|
||||
# user has no test drives, no credit card on file, but attempts to book a lesson
|
||||
booking = LessonBooking.book_test_drive(user, teacher_user, valid_single_slots, "Hey I've heard of you before.")
|
||||
booking.errors.any?.should be_false
|
||||
|
|
@ -28,20 +32,24 @@ 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
|
||||
|
||||
user.reload
|
||||
user.remaining_test_drives.should eql 0
|
||||
|
||||
########## Need validate their credit card
|
||||
token = create_stripe_token
|
||||
result = user.payment_update({token: token, zip: '78759', test_drive: true})
|
||||
user.reload
|
||||
user.remaining_test_drives.should eql 3
|
||||
result = user.payment_update({token: token, zip: '78759', test_drive: true, booking_id: booking.id})
|
||||
booking = result[:lesson]
|
||||
lesson = booking.lesson_sessions[0]
|
||||
test_drive = result[:test_drive]
|
||||
booking.errors.any?.should be_false
|
||||
lesson = booking.lesson_sessions[0]
|
||||
|
||||
lesson.errors.any?.should be_false
|
||||
test_drive = result[:test_drive]
|
||||
test_drive.errors.any?.should be_false
|
||||
|
||||
user.reload
|
||||
user.remaining_test_drives.should eql 1
|
||||
|
||||
booking.card_presumed_ok.should be_true
|
||||
booking.sent_notices.should be_true
|
||||
lesson.music_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)
|
||||
|
|
@ -49,20 +57,20 @@ describe "TestDrive Lesson Flow" do
|
|||
|
||||
|
||||
test_drive.stripe_charge_id.should_not be_nil
|
||||
test_drive.recurly_tax_in_cents.should be 412
|
||||
test_drive.recurly_total_in_cents.should eql 4999 + 412
|
||||
test_drive.recurly_subtotal_in_cents.should eql 4999
|
||||
test_drive.recurly_tax_in_cents.should be 247
|
||||
test_drive.recurly_total_in_cents.should eql 2999 + 247
|
||||
test_drive.recurly_subtotal_in_cents.should eql 2999
|
||||
test_drive.recurly_currency.should eql 'USD'
|
||||
line_item = test_drive.sale_line_items[0]
|
||||
line_item.quantity.should eql 1
|
||||
line_item.product_type.should eql SaleLineItem::LESSON
|
||||
line_item.product_id.should eq LessonPackageType.test_drive.id
|
||||
line_item.product_id.should eq LessonPackageType.test_drive_2.id
|
||||
user.reload
|
||||
user.stripe_customer_id.should_not be nil
|
||||
user.lesson_purchases.length.should eql 1
|
||||
user.remaining_test_drives.should eql 3
|
||||
user.remaining_test_drives.should eql 1
|
||||
lesson_purchase = user.lesson_purchases[0]
|
||||
lesson_purchase.price.should eql 49.99
|
||||
lesson_purchase.price.should eql 29.99
|
||||
lesson_purchase.lesson_package_type.is_test_drive?.should eql true
|
||||
|
||||
customer = Stripe::Customer.retrieve(user.stripe_customer_id)
|
||||
|
|
@ -134,7 +142,7 @@ describe "TestDrive Lesson Flow" do
|
|||
lesson_session.music_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)
|
||||
booking.status.should eql LessonBooking::STATUS_APPROVED
|
||||
|
||||
UserMailer.deliveries.length.should eql 4
|
||||
UserMailer.deliveries.length.should eql 2
|
||||
chat = ChatMessage.unscoped.order(:created_at).last
|
||||
chat.message.should eql 'Yeah I got this'
|
||||
chat.channel.should eql ChatMessage::CHANNEL_LESSON
|
||||
|
|
@ -145,7 +153,7 @@ describe "TestDrive Lesson Flow" do
|
|||
notification.student_directed.should eql true
|
||||
notification.purpose.should eql 'accept'
|
||||
notification.description.should eql NotificationTypes::LESSON_MESSAGE
|
||||
notification.message.should eql "Your lesson request is confirmed!"
|
||||
notification.message.should be_nil
|
||||
|
||||
|
||||
# teacher & student get into session
|
||||
|
|
@ -156,6 +164,7 @@ describe "TestDrive Lesson Flow" do
|
|||
lesson_session.music_session.session_removed_at = end_time
|
||||
lesson_session.music_session.save!
|
||||
|
||||
Timecop.travel(end_time + 1)
|
||||
|
||||
|
||||
UserMailer.deliveries.clear
|
||||
|
|
@ -173,11 +182,11 @@ describe "TestDrive Lesson Flow" do
|
|||
lesson_session.billing_error_reason.should be_nil
|
||||
lesson_session.sent_notices.should be true
|
||||
purchase = lesson_session.lesson_package_purchase
|
||||
purchase.should_not be nil
|
||||
purchase.price_in_cents.should eql 4999
|
||||
purchase.should_not be_nil
|
||||
purchase.price_in_cents.should eql 2999
|
||||
purchase.lesson_package_type.is_test_drive?.should be true
|
||||
user.reload
|
||||
user.remaining_test_drives.should eql 3
|
||||
user.remaining_test_drives.should eql 1
|
||||
UserMailer.deliveries.length.should eql 2 # one for student, one for teacher
|
||||
|
||||
teacher_distribution = lesson_session.teacher_distribution
|
||||
|
|
@ -194,7 +203,7 @@ describe "TestDrive Lesson Flow" do
|
|||
teacher_distribution.distributed.should be_false
|
||||
|
||||
TeacherPayment.count.should eql 0
|
||||
TeacherPayment.daily_check
|
||||
TeacherPayment.hourly_check
|
||||
TeacherPayment.count.should eql 1
|
||||
|
||||
lesson_session.reload
|
||||
|
|
|
|||
|
|
@ -783,6 +783,22 @@ describe AffiliatePartner do
|
|||
end
|
||||
end
|
||||
|
||||
describe "edge case" do
|
||||
it "year change" do
|
||||
partner.touch
|
||||
last_day_of_year = Date.new(2015, 12, 31)
|
||||
first_day_of_next_year = Date.new(2016, 01, 01)
|
||||
AffiliatePartner.tally_up(last_day_of_year)
|
||||
AffiliatePartner.tally_up(first_day_of_next_year)
|
||||
quarterly_payment = AffiliateQuarterlyPayment.where(year: 2016, quarter: 0, affiliate_partner_id: partner.id).first
|
||||
quarterly_payment.closed.should be_false
|
||||
AffiliatePartner.tally_up(Date.new(2016, 01, 02))
|
||||
quarterly_payment.reload
|
||||
quarterly_payment.closed.should be_false
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
describe "boundary_dates_for_month" do
|
||||
it "invalid month" do
|
||||
expect{AffiliatePartner.boundary_dates_for_month(2015, 0)}.to raise_error
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Language do
|
||||
|
||||
it "english_sort" do
|
||||
sorted= Language.english_sort
|
||||
sorted[0].id.should eql 'EN'
|
||||
sorted[1].id.should eql 'AF'
|
||||
sorted[-1].id.should eql 'XH'
|
||||
end
|
||||
end
|
||||
|
|
@ -112,7 +112,7 @@ describe LessonBooking do
|
|||
purchase.last_billing_attempt_at.should eql time
|
||||
purchase.sent_billing_notices.should eql false
|
||||
|
||||
user.card_approved(create_stripe_token, '78759')
|
||||
user.card_approved(create_stripe_token, '78759', booking.id)
|
||||
user.save!
|
||||
|
||||
day = day + 1
|
||||
|
|
@ -137,7 +137,7 @@ describe LessonBooking do
|
|||
end
|
||||
|
||||
it "advances to next month" do
|
||||
user.card_approved(create_stripe_token, '78759')
|
||||
user.card_approved(create_stripe_token, '78759', nil)
|
||||
user.save!
|
||||
|
||||
day = Date.new(2016, 1, 20)
|
||||
|
|
@ -258,7 +258,7 @@ describe LessonBooking do
|
|||
purchase.billed.should be false
|
||||
|
||||
# now that it's suspended, let's unsuspend it
|
||||
user.card_approved(create_stripe_token, '78759')
|
||||
user.card_approved(create_stripe_token, '78759', booking.id)
|
||||
user.save!
|
||||
|
||||
day = day + 1
|
||||
|
|
@ -386,38 +386,6 @@ describe LessonBooking do
|
|||
end
|
||||
|
||||
describe "book_free" do
|
||||
it "works" 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
|
||||
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_FREE
|
||||
booking.lesson_booking_slots.length.should eq 2
|
||||
|
||||
chat_message = ChatMessage.where(lesson_booking_id: booking.id).first
|
||||
chat_message.should_not be_nil
|
||||
chat_message.message.should eq booking.description
|
||||
|
||||
user.reload
|
||||
user.remaining_free_lessons.should eq 0
|
||||
user.remaining_test_drives.should eq 1
|
||||
|
||||
booking.card_presumed_ok.should eq false
|
||||
booking.sent_notices.should eq false
|
||||
|
||||
user.card_approved(create_stripe_token, '78759')
|
||||
user.save!
|
||||
booking.reload
|
||||
booking.sent_notices.should eq true
|
||||
booking.card_presumed_ok.should eq true
|
||||
|
||||
end
|
||||
|
||||
it "allows long message to flow through chat" do
|
||||
|
||||
|
|
@ -426,7 +394,7 @@ describe LessonBooking do
|
|||
|
||||
booking.errors.any?.should be false
|
||||
|
||||
chat_message = ChatMessage.where(lesson_booking_id: booking.id).first
|
||||
chat_message = ChatMessage.where(lesson_session_id: booking.next_lesson.id).first
|
||||
chat_message.should_not be_nil
|
||||
chat_message.message.should eq booking.description
|
||||
end
|
||||
|
|
@ -446,16 +414,6 @@ describe LessonBooking do
|
|||
ChatMessage.count.should eq 1
|
||||
end
|
||||
|
||||
it "prevents user without stored credit card" do
|
||||
|
||||
pending "free not supported"
|
||||
user.stored_credit_card = false
|
||||
user.save!
|
||||
|
||||
booking = LessonBooking.book_free(user, teacher_user, valid_single_slots, "Hey I've heard of you before.")
|
||||
booking.errors.any?.should be false
|
||||
end
|
||||
|
||||
it "must have 2 lesson booking slots" do
|
||||
|
||||
booking = LessonBooking.book_test_drive(user, teacher_user, [], "Hey I've heard of you before.")
|
||||
|
|
@ -488,7 +446,7 @@ describe LessonBooking do
|
|||
booking.lesson_type.should eq LessonBooking::LESSON_TYPE_TEST_DRIVE
|
||||
booking.lesson_booking_slots.length.should eq 2
|
||||
|
||||
chat_message = ChatMessage.where(lesson_booking_id: booking.id).first
|
||||
chat_message = ChatMessage.where(lesson_session_id: booking.next_lesson.id).first
|
||||
chat_message.should_not be_nil
|
||||
chat_message.message.should eq booking.description
|
||||
|
||||
|
|
@ -502,7 +460,7 @@ describe LessonBooking do
|
|||
|
||||
booking.errors.any?.should be false
|
||||
|
||||
chat_message = ChatMessage.where(lesson_booking_id: booking.id).first
|
||||
chat_message = ChatMessage.where(lesson_session_id: booking.next_lesson.id).first
|
||||
chat_message.should_not be_nil
|
||||
chat_message.message.should eq booking.description
|
||||
end
|
||||
|
|
@ -520,7 +478,7 @@ describe LessonBooking do
|
|||
|
||||
booking = LessonBooking.book_test_drive(user, teacher_user, valid_single_slots, "Hey I've heard of you before.")
|
||||
booking.errors.any?.should be true
|
||||
booking.errors[:user].should eq ["has a requested TestDrive with this teacher"]
|
||||
booking.errors[:user].should eq ["have a requested TestDrive with this teacher"]
|
||||
|
||||
ChatMessage.count.should eq 1
|
||||
end
|
||||
|
|
@ -549,7 +507,7 @@ describe LessonBooking do
|
|||
booking.lesson_type.should eq LessonBooking::LESSON_TYPE_PAID
|
||||
booking.lesson_booking_slots.length.should eq 2
|
||||
|
||||
chat_message = ChatMessage.where(lesson_booking_id: booking.id).first
|
||||
chat_message = ChatMessage.where(lesson_session_id: booking.next_lesson.id).first
|
||||
chat_message.should_not be_nil
|
||||
chat_message.message.should eq booking.description
|
||||
|
||||
|
|
@ -570,7 +528,7 @@ describe LessonBooking do
|
|||
booking.lesson_type.should eq LessonBooking::LESSON_TYPE_PAID
|
||||
booking.lesson_booking_slots.length.should eq 2
|
||||
|
||||
chat_message = ChatMessage.where(lesson_booking_id: booking.id).first
|
||||
chat_message = ChatMessage.where(lesson_session_id: booking.next_lesson.id).first
|
||||
chat_message.should_not be_nil
|
||||
chat_message.message.should eq booking.description
|
||||
|
||||
|
|
@ -579,12 +537,12 @@ describe LessonBooking do
|
|||
user.remaining_test_drives.should eq 1
|
||||
end
|
||||
|
||||
it "allows long message to flow through chat" do
|
||||
it "allows long message to flow through chat" do
|
||||
booking = LessonBooking.book_normal(user, teacher_user, valid_recurring_slots, Faker::Lorem.characters(10000), true, LessonBooking::PAYMENT_STYLE_WEEKLY, 60)
|
||||
|
||||
booking.errors.any?.should be false
|
||||
|
||||
chat_message = ChatMessage.where(lesson_booking_id: booking.id).first
|
||||
chat_message = ChatMessage.where(lesson_session_id: booking.next_lesson.id).first
|
||||
chat_message.should_not be_nil
|
||||
chat_message.message.should eq booking.description
|
||||
end
|
||||
|
|
@ -709,6 +667,7 @@ describe LessonBooking do
|
|||
Timecop.freeze(7.days.ago)
|
||||
lesson_session.cancel({canceler: teacher_user, message: 'meh', slot: booking.default_slot.id, update_all: false})
|
||||
lesson_session.errors.any?.should be_false
|
||||
lesson_session.reload
|
||||
lesson_session.status.should eql LessonSession::STATUS_CANCELED
|
||||
lesson_session.reload
|
||||
booking.reload
|
||||
|
|
@ -732,8 +691,8 @@ describe LessonBooking do
|
|||
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.status.should eql LessonSession::STATUS_CANCELED
|
||||
booking.reload
|
||||
booking.status.should eql LessonSession::STATUS_CANCELED
|
||||
UserMailer.deliveries.length.should eql 2
|
||||
|
|
@ -784,8 +743,8 @@ describe LessonBooking do
|
|||
Timecop.freeze(7.days.ago)
|
||||
lesson_session.cancel({canceler: user, message: 'meh', slot: booking.default_slot.id, update_all: true})
|
||||
lesson_session.errors.any?.should be_false
|
||||
lesson_session.status.should eql LessonSession::STATUS_CANCELED
|
||||
lesson_session.reload
|
||||
lesson_session.status.should eql LessonSession::STATUS_CANCELED
|
||||
booking.reload
|
||||
booking.status.should eql LessonSession::STATUS_CANCELED
|
||||
booking.canceler.should eql user
|
||||
|
|
|
|||
|
|
@ -13,6 +13,32 @@ describe LessonSessionAnalyser do
|
|||
let(:valid_recurring_slots) { [lesson_booking_slot_recurring1, lesson_booking_slot_recurring2] }
|
||||
|
||||
describe "analyse" do
|
||||
|
||||
after{
|
||||
Timecop.return
|
||||
}
|
||||
it "neither show" do
|
||||
lesson = testdrive_lesson(user, teacher)
|
||||
music_session = lesson.music_session
|
||||
|
||||
Timecop.freeze((lesson.music_session.scheduled_start + lesson.duration * 60) + 1)
|
||||
|
||||
analysis = LessonSessionAnalyser.analyse(lesson)
|
||||
analysis[:reason].should eql LessonSessionAnalyser::TEACHER_FAULT
|
||||
analysis[:student].should eql nil
|
||||
analysis[:bill].should be false
|
||||
|
||||
student = analysis[:student_analysis]
|
||||
student[:joined_on_time].should be false
|
||||
student[:joined_late].should be false
|
||||
student[:waited_correctly].should be false
|
||||
student[:initial_waiting_pct].should eql nil
|
||||
student[:potential_waiting_time].should eql nil
|
||||
|
||||
together = analysis[:together_analysis]
|
||||
together[:session_time].should eql 0
|
||||
end
|
||||
|
||||
it "teacher joined on time, waited, student no show" do
|
||||
lesson = testdrive_lesson(user, teacher)
|
||||
music_session = lesson.music_session
|
||||
|
|
@ -21,8 +47,7 @@ describe LessonSessionAnalyser do
|
|||
start = lesson.scheduled_start
|
||||
end_time = lesson.scheduled_start + (60 * lesson.duration)
|
||||
uh2 = FactoryGirl.create(:music_session_user_history, user: teacher, history: music_session, created_at: start, session_removed_at: end_time)
|
||||
lesson.music_session.session_removed_at = end_time
|
||||
lesson.music_session.save!
|
||||
Timecop.travel(end_time + 1)
|
||||
|
||||
|
||||
analysis = LessonSessionAnalyser.analyse(lesson)
|
||||
|
|
@ -41,6 +66,36 @@ describe LessonSessionAnalyser do
|
|||
together[:session_time].should eql 0
|
||||
end
|
||||
|
||||
it "student joined 1 min before start time, is waiting for 12 minutes" do
|
||||
lesson = testdrive_lesson(user, teacher)
|
||||
music_session = lesson.music_session
|
||||
|
||||
# create some bogus, super-perfect teacher/student times
|
||||
start = lesson.scheduled_start
|
||||
end_time = lesson.scheduled_start + (60 * lesson.duration)
|
||||
uh2 = FactoryGirl.create(:music_session_user_history, user: user, history: music_session, created_at: start - 60, session_removed_at: nil)
|
||||
|
||||
Timecop.freeze(start + 11 * 60)
|
||||
|
||||
analysis = LessonSessionAnalyser.analyse(lesson, true)
|
||||
analysis[:reason].should eql LessonSessionAnalyser::TEACHER_FAULT
|
||||
analysis[:teacher].should eql LessonSessionAnalyser::NO_SHOW
|
||||
analysis[:student].should be_nil
|
||||
analysis[:bill].should be false
|
||||
|
||||
student = analysis[:student_analysis]
|
||||
student[:joined_on_time].should be true
|
||||
student[:joined_late].should be false
|
||||
student[:waited_correctly].should be true
|
||||
student[:initial_waiting_pct].should eql 1.0
|
||||
student[:potential_waiting_time].should eql 600.0
|
||||
|
||||
student[:session_time].should eql (11 * 60).to_f
|
||||
|
||||
together = analysis[:together_analysis]
|
||||
together[:session_time].should eql 0
|
||||
end
|
||||
|
||||
it "teacher joined on time, waited, student joined late" do
|
||||
lesson = testdrive_lesson(user, teacher)
|
||||
music_session = lesson.music_session
|
||||
|
|
@ -52,12 +107,10 @@ describe LessonSessionAnalyser do
|
|||
uh1 = FactoryGirl.create(:music_session_user_history, user: user, history: music_session, created_at: late_start, session_removed_at: late_start + 4 * 60)
|
||||
uh2 = FactoryGirl.create(:music_session_user_history, user: teacher, history: music_session, created_at: start, session_removed_at: end_time)
|
||||
|
||||
lesson.music_session.session_removed_at = end_time
|
||||
lesson.music_session.save!
|
||||
Timecop.travel(end_time + 1)
|
||||
|
||||
|
||||
analysis = LessonSessionAnalyser.analyse(lesson)
|
||||
puts analysis
|
||||
analysis[:reason].should eql LessonSessionAnalyser::STUDENT_FAULT
|
||||
analysis[:student].should eql LessonSessionAnalyser::JOINED_LATE
|
||||
analysis[:bill].should be true
|
||||
|
|
@ -92,8 +145,7 @@ describe LessonSessionAnalyser do
|
|||
analysis = LessonSessionAnalyser.analyse(lesson)
|
||||
analysis[:reason].should eql LessonSessionAnalyser::SESSION_ONGOING
|
||||
|
||||
lesson.music_session.session_removed_at = end_time
|
||||
lesson.music_session.save!
|
||||
Timecop.travel(end_time + 1)
|
||||
|
||||
analysis = LessonSessionAnalyser.analyse(lesson)
|
||||
analysis[:reason].should eql LessonSessionAnalyser::SUCCESS
|
||||
|
|
|
|||
|
|
@ -2,12 +2,12 @@ require 'spec_helper'
|
|||
|
||||
describe LessonSession do
|
||||
|
||||
let(:user) {FactoryGirl.create(:user, stored_credit_card: false, remaining_free_lessons: 1, remaining_test_drives: 1)}
|
||||
let(:user) {FactoryGirl.create(:user, stored_credit_card: true, remaining_free_lessons: 1, remaining_test_drives: 1)}
|
||||
let(:teacher) {FactoryGirl.create(:teacher_user)}
|
||||
let(:slot1) { FactoryGirl.build(:lesson_booking_slot_single) }
|
||||
let(:slot2) { FactoryGirl.build(:lesson_booking_slot_single) }
|
||||
|
||||
let(:lesson_booking) {LessonBooking.book_normal(user, teacher, [slot1, slot2], "Hey I've heard of you before.", false, LessonBooking::PAYMENT_STYLE_SINGLE, 60)}
|
||||
let(:lesson_booking) {b = LessonBooking.book_normal(user, teacher, [slot1, slot2], "Hey I've heard of you before.", false, LessonBooking::PAYMENT_STYLE_SINGLE, 60); b.card_presumed_ok = true; b.save!; b}
|
||||
let(:lesson_session) {lesson_booking.lesson_sessions[0]}
|
||||
|
||||
describe "accept" do
|
||||
|
|
@ -16,10 +16,28 @@ describe LessonSession do
|
|||
end
|
||||
end
|
||||
|
||||
describe "upcoming_sessions_reminder" do
|
||||
it "succeeds" do
|
||||
UserMailer.deliveries.clear
|
||||
LessonSession.upcoming_sessions_reminder
|
||||
lesson_session.touch
|
||||
lesson_session.sent_starting_notice.should be_false
|
||||
lesson_session.is_requested?.should be_true
|
||||
lesson_session.music_session.scheduled_start = 15.minutes.from_now
|
||||
lesson_session.music_session.save!
|
||||
LessonSession.upcoming_sessions_reminder
|
||||
UserMailer.deliveries.count.should eql 2
|
||||
UserMailer.deliveries.clear
|
||||
lesson_session.reload
|
||||
lesson_session.sent_starting_notice.should be_true
|
||||
LessonSession.upcoming_sessions_reminder
|
||||
UserMailer.deliveries.count.should eql 0
|
||||
end
|
||||
end
|
||||
|
||||
describe "index" do
|
||||
it "finds single lesson as student" do
|
||||
|
||||
lesson_booking.touch
|
||||
lesson_session.touch
|
||||
lesson_session.music_session.creator.should eql lesson_session.lesson_booking.user
|
||||
lesson_session.lesson_booking.teacher.should eql teacher
|
||||
|
|
|
|||
|
|
@ -362,6 +362,31 @@ describe MusicSession do
|
|||
end
|
||||
|
||||
describe "scheduled" do
|
||||
|
||||
it "includes any RSVP'ed" do
|
||||
rsvp_request = FactoryGirl.create(:rsvp_request_for_multiple_slots, user: some_user, music_session: music_session1, number: 2, chosen:true)
|
||||
|
||||
approved_rsvps = music_session1.approved_rsvps
|
||||
approved_rsvps.length.should == 2
|
||||
|
||||
|
||||
sessions = MusicSession.scheduled(approved_rsvps[0])
|
||||
sessions.length.should == 1
|
||||
|
||||
sessions = MusicSession.scheduled(approved_rsvps[1])
|
||||
sessions.length.should == 1
|
||||
end
|
||||
|
||||
it "includes invited" do
|
||||
invitee = FactoryGirl.create(:user, last_jam_audio_latency: 30, last_jam_locidispid: 3)
|
||||
FactoryGirl.create(:friendship, user: creator, friend: invitee)
|
||||
FactoryGirl.create(:friendship, user: invitee, friend: creator)
|
||||
music_session = FactoryGirl.create(:music_session, creator: creator)
|
||||
FactoryGirl.create(:invitation, receiver:invitee, sender:creator, music_session: music_session)
|
||||
|
||||
sessions = MusicSession.scheduled(invitee)
|
||||
sessions.length.should == 1
|
||||
end
|
||||
it "excludes based on time-range" do
|
||||
session = FactoryGirl.create(:music_session, scheduled_start: Time.now)
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,9 @@ describe Sale do
|
|||
let(:jam_track3) { FactoryGirl.create(:jam_track) }
|
||||
let(:gift_card) { GiftCardType.jam_track_5 }
|
||||
|
||||
before(:each) {
|
||||
Timecop.return
|
||||
}
|
||||
def assert_free_line_item(sale_line_item, jamtrack)
|
||||
sale_line_item.recurly_tax_in_cents.should be_nil
|
||||
sale_line_item.recurly_total_in_cents.should be_nil
|
||||
|
|
@ -596,6 +599,8 @@ describe Sale do
|
|||
lesson_session.music_session.session_removed_at = end_time
|
||||
lesson_session.music_session.save!
|
||||
|
||||
Timecop.travel(end_time + 1)
|
||||
|
||||
# bill the user
|
||||
LessonSession.hourly_check
|
||||
|
||||
|
|
@ -649,6 +654,8 @@ describe Sale do
|
|||
lesson_session.music_session.session_removed_at = end_time
|
||||
lesson_session.music_session.save!
|
||||
|
||||
Timecop.travel(end_time + 1)
|
||||
|
||||
# bill the user
|
||||
LessonSession.hourly_check
|
||||
|
||||
|
|
@ -715,7 +722,7 @@ describe Sale do
|
|||
booking.should eql user.unprocessed_test_drive
|
||||
|
||||
token = create_stripe_token
|
||||
result = user.payment_update({token: token, zip: '72205', test_drive: true})
|
||||
result = user.payment_update({token: token, zip: '72205', test_drive: true, booking_id: booking.id})
|
||||
|
||||
booking.reload
|
||||
booking.card_presumed_ok.should be_true
|
||||
|
|
@ -731,7 +738,7 @@ describe Sale do
|
|||
line_item = sale.sale_line_items[0]
|
||||
line_item.quantity.should eql 1
|
||||
line_item.product_type.should eql SaleLineItem::LESSON
|
||||
line_item.product_id.should eq LessonPackageType.test_drive.id
|
||||
line_item.product_id.should eq LessonPackageType.test_drive_4.id
|
||||
|
||||
user.reload
|
||||
user.stripe_customer_id.should_not be nil
|
||||
|
|
@ -762,7 +769,7 @@ describe Sale do
|
|||
user.remaining_test_drives.should eql 0
|
||||
|
||||
token = create_stripe_token
|
||||
result = user.payment_update({token: token, zip: '78759', test_drive: true})
|
||||
result = user.payment_update({token: token, zip: '78759', test_drive: true, booking_id: booking.id})
|
||||
|
||||
booking.reload
|
||||
booking.card_presumed_ok.should be_true
|
||||
|
|
@ -778,7 +785,7 @@ describe Sale do
|
|||
line_item = sale.sale_line_items[0]
|
||||
line_item.quantity.should eql 1
|
||||
line_item.product_type.should eql SaleLineItem::LESSON
|
||||
line_item.product_id.should eq LessonPackageType.test_drive.id
|
||||
line_item.product_id.should eq LessonPackageType.test_drive_4.id
|
||||
|
||||
|
||||
user.reload
|
||||
|
|
@ -819,7 +826,7 @@ describe Sale do
|
|||
line_item = sale.sale_line_items[0]
|
||||
line_item.quantity.should eql 1
|
||||
line_item.product_type.should eql SaleLineItem::LESSON
|
||||
line_item.product_id.should eq LessonPackageType.test_drive.id
|
||||
line_item.product_id.should eq LessonPackageType.test_drive_4.id
|
||||
end
|
||||
|
||||
it "will reject second test drive purchase" do
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe TeacherDistribution do
|
||||
|
||||
let(:teacher) {FactoryGirl.create(:teacher_user)}
|
||||
|
||||
|
||||
describe "index" do
|
||||
it "empty" do
|
||||
TeacherDistribution.index(teacher, {})[:query].count.should eql 0
|
||||
end
|
||||
|
||||
it "returns single" do
|
||||
distribution = FactoryGirl.create(:teacher_distribution, teacher: teacher)
|
||||
|
||||
TeacherDistribution.index(teacher, {})[:query].count.should eql 1
|
||||
|
||||
distribution = FactoryGirl.create(:teacher_distribution) # some random teacher
|
||||
|
||||
TeacherDistribution.index(teacher, {})[:query].count.should eql 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -6,14 +6,17 @@ describe TeacherPayment do
|
|||
let(:user2) { FactoryGirl.create(:user) }
|
||||
let(:teacher_obj) {FactoryGirl.create(:teacher, stripe_account_id: stripe_account1_id)}
|
||||
let(:teacher_obj2) {FactoryGirl.create(:teacher, stripe_account_id: stripe_account2_id)}
|
||||
let(:school_owner_teacher) {FactoryGirl.create(:teacher, stripe_account_id: stripe_account2_id)}
|
||||
let(:teacher) { FactoryGirl.create(:user, teacher: teacher_obj) }
|
||||
let(:teacher2) { FactoryGirl.create(:user, teacher: teacher_obj2) }
|
||||
let(:school_teacher) { FactoryGirl.create(:user, teacher: school_owner_teacher)}
|
||||
let(:test_drive_lesson) {testdrive_lesson(user, teacher)}
|
||||
let(:test_drive_lesson2) {testdrive_lesson(user2, teacher2)}
|
||||
let(:test_drive_distribution) {FactoryGirl.create(:teacher_distribution, lesson_session: test_drive_lesson, teacher: teacher, teacher_payment: nil, ready:false)}
|
||||
let(:test_drive_distribution2) {FactoryGirl.create(:teacher_distribution, lesson_session: test_drive_lesson2, teacher: teacher2, teacher_payment: nil, ready:false)}
|
||||
let(:normal_lesson_session) {normal_lesson(user, teacher)}
|
||||
let(:normal_distribution) {FactoryGirl.create(:teacher_distribution, lesson_session: normal_lesson_session, teacher: teacher, teacher_payment: nil, ready:false)}
|
||||
let(:school) {FactoryGirl.create(:school, user: school_teacher)}
|
||||
|
||||
describe "pending_teacher_payments" do
|
||||
|
||||
|
|
@ -35,6 +38,21 @@ describe TeacherPayment do
|
|||
payments[0]['id'].should eql teacher.id
|
||||
end
|
||||
|
||||
it "school distribution" do
|
||||
test_drive_distribution.school = school
|
||||
test_drive_distribution.save!
|
||||
|
||||
payments = TeacherPayment.pending_teacher_payments
|
||||
payments.count.should eql 0
|
||||
|
||||
test_drive_distribution.ready = true
|
||||
test_drive_distribution.save!
|
||||
|
||||
payments = TeacherPayment.pending_teacher_payments
|
||||
payments.count.should eql 1
|
||||
payments[0]['id'].should eql teacher.id
|
||||
end
|
||||
|
||||
it "multiple teachers" do
|
||||
test_drive_distribution.touch
|
||||
test_drive_distribution2.touch
|
||||
|
|
@ -95,6 +113,7 @@ describe TeacherPayment do
|
|||
|
||||
normal_distribution.ready = true
|
||||
normal_distribution.save!
|
||||
UserMailer.deliveries.clear
|
||||
|
||||
TeacherPayment.teacher_payments
|
||||
|
||||
|
|
@ -108,9 +127,13 @@ describe TeacherPayment do
|
|||
puts payment.teacher_payment_charge.billing_error_reason
|
||||
puts payment.teacher_payment_charge.billing_error_detail
|
||||
end
|
||||
|
||||
# only one confirm email to teacher
|
||||
UserMailer.deliveries.length.should eql 1
|
||||
payment.teacher_payment_charge.billed.should eql true
|
||||
payment.teacher_payment_charge.amount_in_cents.should eql 1000
|
||||
payment.teacher_payment_charge.fee_in_cents.should eql 280
|
||||
payment.teacher_payment_charge.teacher.should eql teacher
|
||||
teacher_distribution = payment.teacher_payment_charge.distribution
|
||||
teacher_distribution.amount_in_cents.should eql 1000
|
||||
charge = Stripe::Charge.retrieve(payment.teacher_payment_charge.stripe_charge_id)
|
||||
|
|
@ -118,6 +141,39 @@ describe TeacherPayment do
|
|||
charge.application_fee.should include("fee_")
|
||||
end
|
||||
|
||||
it "charges school" do
|
||||
normal_distribution.school = school
|
||||
normal_distribution.ready = true
|
||||
normal_distribution.save!
|
||||
|
||||
UserMailer.deliveries.clear
|
||||
TeacherPayment.teacher_payments
|
||||
|
||||
normal_distribution.reload
|
||||
normal_distribution.teacher_payment.should_not be_nil
|
||||
normal_distribution.teacher_payment.school.should eql school
|
||||
TeacherPayment.count.should eql 1
|
||||
|
||||
payment = normal_distribution.teacher_payment
|
||||
|
||||
if payment.teacher_payment_charge.billing_error_reason
|
||||
puts payment.teacher_payment_charge.billing_error_reason
|
||||
puts payment.teacher_payment_charge.billing_error_detail
|
||||
end
|
||||
# one to school owner, one to teacher
|
||||
UserMailer.deliveries.length.should eql 2
|
||||
payment.teacher_payment_charge.billed.should eql true
|
||||
payment.teacher_payment_charge.amount_in_cents.should eql 1000
|
||||
payment.teacher_payment_charge.fee_in_cents.should eql 280
|
||||
payment.teacher_payment_charge.user.should eql school.owner
|
||||
teacher_distribution = payment.teacher_payment_charge.distribution
|
||||
teacher_distribution.amount_in_cents.should eql 1000
|
||||
charge = Stripe::Charge.retrieve(payment.teacher_payment_charge.stripe_charge_id)
|
||||
charge.destination.should eql school.owner.teacher.stripe_account_id
|
||||
charge.amount.should eql 1000
|
||||
charge.application_fee.should include("fee_")
|
||||
end
|
||||
|
||||
it "charges multiple" do
|
||||
test_drive_distribution.touch
|
||||
test_drive_distribution.ready = true
|
||||
|
|
@ -240,6 +296,76 @@ describe TeacherPayment do
|
|||
charge.amount.should eql 1000
|
||||
end
|
||||
|
||||
it "failed payment, then success (school)" do
|
||||
StripeMock.prepare_card_error(:card_declined)
|
||||
|
||||
normal_distribution.school = school
|
||||
normal_distribution.ready = true
|
||||
normal_distribution.save!
|
||||
|
||||
TeacherPayment.teacher_payments
|
||||
|
||||
normal_distribution.reload
|
||||
normal_distribution.teacher_payment.should_not be_nil
|
||||
TeacherPayment.count.should eql 1
|
||||
|
||||
payment = normal_distribution.teacher_payment
|
||||
|
||||
payment.teacher_payment_charge.billing_error_reason.should eql("card_declined")
|
||||
payment.teacher_payment_charge.billing_error_detail.should include("declined")
|
||||
|
||||
payment.teacher_payment_charge.billed.should eql false
|
||||
payment.teacher_payment_charge.amount_in_cents.should eql 1000
|
||||
payment.teacher_payment_charge.fee_in_cents.should eql 280
|
||||
teacher_distribution = payment.teacher_payment_charge.distribution
|
||||
teacher_distribution.amount_in_cents.should eql 1000
|
||||
|
||||
payment.teacher_payment_charge.stripe_charge_id.should be_nil
|
||||
|
||||
StripeMock.clear_errors
|
||||
|
||||
TeacherPayment.teacher_payments
|
||||
|
||||
normal_distribution.reload
|
||||
normal_distribution.teacher_payment.should_not be_nil
|
||||
TeacherPayment.count.should eql 1
|
||||
|
||||
# make sure the teacher_payment is reused, and charge is reused
|
||||
normal_distribution.teacher_payment.should eql(payment)
|
||||
normal_distribution.teacher_payment.teacher_payment_charge.should eql(payment.teacher_payment_charge)
|
||||
|
||||
# no attempt should be made because a day hasn't gone by
|
||||
payment = normal_distribution.teacher_payment
|
||||
payment.teacher_payment_charge.billed.should eql false
|
||||
payment.teacher_payment_charge.amount_in_cents.should eql 1000
|
||||
payment.teacher_payment_charge.fee_in_cents.should eql 280
|
||||
teacher_distribution = payment.teacher_payment_charge.distribution
|
||||
teacher_distribution.amount_in_cents.should eql 1000
|
||||
|
||||
# advance one day so that a charge is attempted again
|
||||
Timecop.freeze(Date.today + 2)
|
||||
|
||||
TeacherPayment.teacher_payments
|
||||
normal_distribution.reload
|
||||
normal_distribution.teacher_payment.should_not be_nil
|
||||
TeacherPayment.count.should eql 1
|
||||
|
||||
# make sure the teacher_payment is reused, and charge is reused
|
||||
normal_distribution.teacher_payment.should eql(payment)
|
||||
normal_distribution.teacher_payment.teacher_payment_charge.should eql(payment.teacher_payment_charge)
|
||||
|
||||
# no attempt should be made because a day hasn't gone by
|
||||
payment = normal_distribution.teacher_payment
|
||||
payment.reload
|
||||
payment.teacher_payment_charge.billed.should eql true
|
||||
payment.teacher_payment_charge.amount_in_cents.should eql 1000
|
||||
payment.teacher_payment_charge.fee_in_cents.should eql 280
|
||||
teacher_distribution = payment.teacher_payment_charge.distribution
|
||||
teacher_distribution.amount_in_cents.should eql 1000
|
||||
charge = Stripe::Charge.retrieve(payment.teacher_payment_charge.stripe_charge_id)
|
||||
charge.amount.should eql 1000
|
||||
end
|
||||
|
||||
it "charges multiple (with initial failure)" do
|
||||
StripeMock.prepare_card_error(:card_declined)
|
||||
|
||||
|
|
|
|||
|
|
@ -842,6 +842,45 @@ describe User do
|
|||
end
|
||||
end
|
||||
|
||||
describe "uncollectables" do
|
||||
let(:user) {FactoryGirl.create(:user)}
|
||||
let(:teacher) {FactoryGirl.create(:teacher_user)}
|
||||
|
||||
|
||||
it "empty" do
|
||||
user.uncollectables.count.should eql 0
|
||||
end
|
||||
|
||||
it "one" do
|
||||
lesson_session = normal_lesson(user, teacher)
|
||||
lesson_session.lesson_payment_charge.user.should eql user
|
||||
lesson_session.lesson_payment_charge.billing_attempts = 1
|
||||
lesson_session.lesson_payment_charge.save!
|
||||
uncollectables = user.uncollectables
|
||||
uncollectables.count.should eql 1
|
||||
uncollectable = uncollectables[0]
|
||||
uncollectable.description.should_not be_nil
|
||||
uncollectable.expected_price_in_cents.should eql 3000
|
||||
uncollectable.is_card_declined?.should be_false
|
||||
end
|
||||
|
||||
it "for monthly" do
|
||||
lesson_session = monthly_lesson(user, teacher)
|
||||
lesson_session.booked_price.should eql 30.00
|
||||
LessonBooking.hourly_check
|
||||
lesson_session.lesson_payment_charge.should be_nil
|
||||
purchases=LessonPackagePurchase.where(user_id: user.id)
|
||||
purchases.count.should eql 1
|
||||
purchases[0].lesson_payment_charge.billing_attempts = 1
|
||||
purchases[0].lesson_payment_charge.save!
|
||||
uncollectables = user.uncollectables
|
||||
uncollectables.count.should eql 1
|
||||
uncollectable = uncollectables[0]
|
||||
uncollectable.description.should_not be_nil
|
||||
uncollectable.expected_price_in_cents.should eql 3000
|
||||
uncollectable.is_card_declined?.should be_false
|
||||
end
|
||||
end
|
||||
=begin
|
||||
describe "update avatar" do
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ describe "RenderMailers", :slow => true do
|
|||
|
||||
it { @filename="welcome_message"; UserMailer.welcome_message(user).deliver }
|
||||
it { @filename="student_welcome_message"; UserMailer.student_welcome_message(user).deliver }
|
||||
it { @filename="school_owner_welcome_message"; UserMailer.school_owner_welcome_message(user).deliver }
|
||||
it { @filename="confirm_email"; UserMailer.confirm_email(user, "/signup").deliver }
|
||||
it { @filename="password_reset"; UserMailer.password_reset(user, '/reset_password').deliver }
|
||||
it { @filename="password_changed"; UserMailer.password_changed(user).deliver }
|
||||
|
|
@ -49,6 +50,7 @@ describe "RenderMailers", :slow => true do
|
|||
@filename = "teacher_welcome_message"
|
||||
UserMailer.teacher_welcome_message(teacher).deliver
|
||||
end
|
||||
|
||||
it "teacher_lesson_request" do
|
||||
@filename = "teacher_lesson_request"
|
||||
|
||||
|
|
@ -120,6 +122,22 @@ describe "RenderMailers", :slow => true do
|
|||
UserMailer.deliveries.clear
|
||||
UserMailer.teacher_lesson_completed(lesson).deliver
|
||||
end
|
||||
|
||||
it "lesson_starting_soon_teacher" do
|
||||
@filename = "lesson_starting_soon_teacher"
|
||||
lesson = testdrive_lesson(user, teacher)
|
||||
|
||||
UserMailer.deliveries.clear
|
||||
UserMailer.lesson_starting_soon_teacher(lesson).deliver
|
||||
end
|
||||
|
||||
it "lesson_starting_soon_student" do
|
||||
@filename = "lesson_starting_soon_student"
|
||||
lesson = testdrive_lesson(user, teacher)
|
||||
|
||||
UserMailer.deliveries.clear
|
||||
UserMailer.lesson_starting_soon_student(lesson).deliver
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ def testdrive_lesson(user, teacher, slots = nil)
|
|||
booking.card_presumed_ok.should be_true
|
||||
|
||||
if user.most_recent_test_drive_purchase.nil?
|
||||
LessonPackagePurchase.create(user, booking, LessonPackageType.test_drive)
|
||||
LessonPackagePurchase.create(user, booking, LessonPackageType.test_drive_4)
|
||||
end
|
||||
|
||||
lesson.accept({message: 'Yeah I got this', slot: slots[0]})
|
||||
|
|
@ -66,7 +66,7 @@ def normal_lesson(user, teacher, slots = nil)
|
|||
booking.card_presumed_ok.should be_true
|
||||
|
||||
#if user.most_recent_test_drive_purchase.nil?
|
||||
# LessonPackagePurchase.create(user, booking, LessonPackageType.test_drive)
|
||||
# LessonPackagePurchase.create(user, booking, LessonPackageType.test_drive_4)
|
||||
#end
|
||||
|
||||
lesson.accept({message: 'Yeah I got this', slot: slots[0]})
|
||||
|
|
@ -74,6 +74,41 @@ def normal_lesson(user, teacher, slots = nil)
|
|||
lesson.reload
|
||||
lesson.slot.should eql slots[0]
|
||||
lesson.status.should eql LessonSession::STATUS_APPROVED
|
||||
lesson.music_session.should_not be_nil
|
||||
|
||||
lesson
|
||||
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
|
||||
end
|
||||
|
|
@ -7,6 +7,10 @@ def app_config
|
|||
'http://localhost:3333'
|
||||
end
|
||||
|
||||
def email_partners_alias
|
||||
'partners@jamkazam.com'
|
||||
end
|
||||
|
||||
def email_social_alias
|
||||
'social@jamkazam.com'
|
||||
end
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ else
|
|||
end
|
||||
|
||||
#gem 'license_finder'
|
||||
gem 'pg_migrate', '0.1.14'
|
||||
gem 'kickbox'
|
||||
gem 'oj', '2.10.2'
|
||||
gem 'builder'
|
||||
|
|
@ -89,7 +90,7 @@ gem 'htmlentities'
|
|||
gem 'sanitize'
|
||||
gem 'recurly'
|
||||
#gem 'guard', '2.7.3'
|
||||
gem 'influxdb' #, '0.1.8'
|
||||
#gem 'influxdb' #, '0.1.8'
|
||||
gem 'cause' # needed by influxdb
|
||||
gem 'influxdb-rails'# , '0.1.10'
|
||||
gem 'sitemap_generator'
|
||||
|
|
@ -142,6 +143,7 @@ group :test, :cucumber do
|
|||
gem 'simplecov', '~> 0.7.1'
|
||||
gem 'simplecov-rcov'
|
||||
gem 'capybara', '2.4.4'
|
||||
gem 'rails-assets-sinon', source: 'https://rails-assets.org'
|
||||
#if ENV['JAMWEB_QT5'] == '1'
|
||||
# # necessary on platforms such as arch linux, where pacman -S qt5-webkit is your easiet option
|
||||
# gem "capybara-webkit", :git => 'git://github.com/thoughtbot/capybara-webkit.git'
|
||||
|
|
@ -159,6 +161,7 @@ group :test, :cucumber do
|
|||
# gem 'growl', '1.0.3'
|
||||
gem 'poltergeist'
|
||||
gem 'resque_spec'
|
||||
gem 'timecop'
|
||||
#gem 'thin'
|
||||
end
|
||||
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 4.0 KiB |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue