* lessons 90% done, but still mostly hidden
This commit is contained in:
parent
557bdc42db
commit
399d010310
|
|
@ -77,6 +77,9 @@ gem 'influxdb', '0.1.8'
|
|||
gem 'influxdb-rails', '0.1.10'
|
||||
gem 'recurly'
|
||||
gem 'sendgrid_toolkit', '>= 1.1.1'
|
||||
gem 'stripe'
|
||||
gem 'zip-codes'
|
||||
gem 'email_validator'
|
||||
|
||||
group :libv8 do
|
||||
gem 'libv8', "~> 4.5.95"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,47 @@
|
|||
ActiveAdmin.register JamRuby::LessonBooking, :as => 'LessonBookings' do
|
||||
|
||||
menu :label => 'LessonBooking', :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.unscoped.order('created_at desc') }
|
||||
scope("Requested") { |scope| scope.unscoped.where(status: LessonBooking::STATUS_REQUESTED).order('created_at desc') }
|
||||
scope("Approved") { |scope| scope.unscoped.approved.order('created_at desc') }
|
||||
scope("Suspended" ) { |scope| scope.unscoped.suspended.order('created_at desc') }
|
||||
scope("Canceled" ) { |scope| scope.unscoped.canceled.order('created_at desc') }
|
||||
|
||||
index do
|
||||
column "User Link" do |lesson_booking|
|
||||
span do
|
||||
link_to "Web URL", "#{Rails.application.config.external_root_url}/client#/jamclass/lesson-booking/#{lesson_booking.id}"
|
||||
end
|
||||
end
|
||||
column "Type" do |lesson_booking|
|
||||
lesson_booking.display_type
|
||||
end
|
||||
column "Status" do |lesson_booking|
|
||||
lesson_booking.status
|
||||
end
|
||||
column "Teacher" do |lesson_booking|
|
||||
teacher = lesson_booking.teacher
|
||||
span do
|
||||
link_to "#{teacher.name} (#{teacher.email})", "#{Rails.application.config.external_root_url}/client#/profile/teacher/#{teacher.id}"
|
||||
end
|
||||
end
|
||||
column "Student" do |lesson_booking|
|
||||
student = lesson_booking.student
|
||||
span do
|
||||
link_to "#{student.name} (#{student.email})", "#{Rails.application.config.external_root_url}/client#/profile/#{student.id}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
show do
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
ActiveAdmin.register JamRuby::LessonSession, :as => 'LessonSessions' do
|
||||
|
||||
menu :label => 'LessonSession', :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.unscoped.order('created_at desc') }
|
||||
scope("Requested" ) { |scope| scope.unscoped.where(status: LessonBooking::STATUS_REQUESTED).order('created_at desc') }
|
||||
scope("Approved") { |scope| scope.unscoped.approved.order('created_at desc') }
|
||||
scope("Suspended" ) { |scope| scope.unscoped.suspended.order('created_at desc') }
|
||||
scope("Canceled" ) { |scope| scope.unscoped.canceled.order('created_at desc') }
|
||||
scope("Missed" ) { |scope| scope.unscoped.missed.order('created_at desc') }
|
||||
scope("Completed" ) { |scope| scope.unscoped.completed.order('created_at desc') }
|
||||
|
||||
index do
|
||||
column "User Link" do |lesson_session|
|
||||
lesson_booking = lesson_session.lesson_booking
|
||||
span do
|
||||
link_to "Web URL", "#{Rails.application.config.external_root_url}/client#/jamclass/lesson-booking/#{lesson_booking.id}"
|
||||
end
|
||||
end
|
||||
column "Status" do |lesson_session|
|
||||
lesson_session.status
|
||||
end
|
||||
column "Start Time" do |lesson_session|
|
||||
span do
|
||||
lesson_session.music_session.pretty_scheduled_start(true)
|
||||
end
|
||||
br
|
||||
span do
|
||||
lesson_session.music_session.scheduled_start
|
||||
end
|
||||
end
|
||||
column "Duration" do |lesson_session|
|
||||
lesson_session.duration
|
||||
end
|
||||
column "Teacher" do |lesson_session|
|
||||
teacher = lesson_session.teacher
|
||||
span do
|
||||
link_to "#{teacher.name} (#{teacher.email})", "#{Rails.application.config.external_root_url}/client#/profile/teacher/#{teacher.id}"
|
||||
end
|
||||
end
|
||||
column "Student" do |lesson_session|
|
||||
student = lesson_session.student
|
||||
span do
|
||||
link_to "#{student.name} (#{student.email})", "#{Rails.application.config.external_root_url}/client#/profile/#{student.id}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
show do
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -15,7 +15,6 @@ ActiveAdmin.register_page "Monthly Stats" do
|
|||
column "Sessions", :count
|
||||
end
|
||||
|
||||
|
||||
h2 "Distinct Users Who Played with a JamTrack"
|
||||
table_for MusicSession.select([:month, :count]).find_by_sql("select date_trunc('month', jts.created_at)::date as month, count(distinct(user_id)) from jam_track_sessions jts group by month order by month desc;") do
|
||||
column "Month", Proc.new { |row| Date.parse(row.month).strftime('%B %Y') }
|
||||
|
|
@ -36,5 +35,4 @@ ActiveAdmin.register_page "Monthly Stats" do
|
|||
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
=begin
|
||||
ActiveAdmin.register JamRuby::User, :as => 'Students' do
|
||||
|
||||
menu :label => 'Students', :parent => 'JamClass'
|
||||
|
|
@ -9,66 +8,25 @@ ActiveAdmin.register JamRuby::User, :as => 'Students' do
|
|||
config.paginate = true
|
||||
|
||||
def booked_anything(scope)
|
||||
scope.joins(lesson_booking)
|
||||
scope.joins(:student_lesson_bookings).where('lesson_bookings.active = true').uniq
|
||||
end
|
||||
scope("Default", default: true) { |scope| booked_anything(scope) }
|
||||
|
||||
scope("Default", default: true) { |scope| booked_anything(scope).order('ready_for_session_at IS NULL DESC') }
|
||||
|
||||
index do
|
||||
column "Name" do |teacher|
|
||||
link_to teacher.user.name, "#{Rails.application.config.external_root_url}/client#/profile/teacher/#{teacher.user.id}"
|
||||
column "Name" do |user|
|
||||
link_to user.name, "#{Rails.application.config.external_root_url}/client#/profile/#{user.id}"
|
||||
end
|
||||
column "Email" do |teacher|
|
||||
teacher.user.email
|
||||
column "Email" do |user|
|
||||
user.email
|
||||
end
|
||||
column "Location" do |teacher|
|
||||
teacher.user.location(country = true)
|
||||
column "Location" do |user|
|
||||
user.location(country = true)
|
||||
end
|
||||
column "Profile %" do |teacher|
|
||||
|
||||
column "Session Ready" do |user|
|
||||
div do
|
||||
span do
|
||||
"#{teacher.pct_complete[:pct]}%"
|
||||
end
|
||||
br
|
||||
span do
|
||||
link_to "Detail", admin_teacher_path(teacher.id)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
column "Background Check" do |teacher|
|
||||
div do
|
||||
if teacher.background_check_at
|
||||
span do
|
||||
teacher.background_check_at.to_date
|
||||
end
|
||||
span do
|
||||
br
|
||||
end
|
||||
span do
|
||||
link_to(mark_background_check_admin_teacher_path(teacher.id), {confirm: "Mark as background checked?"}) do
|
||||
"mark as checked"
|
||||
end
|
||||
end
|
||||
|
||||
else
|
||||
span do
|
||||
'NOT DONE'
|
||||
end
|
||||
span do
|
||||
br
|
||||
end
|
||||
span do
|
||||
link_to("mark as checked", mark_background_check_admin_teacher_path(teacher.id), {confirm: "Mark as background checked?"})
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
column "Session Ready" do |teacher|
|
||||
div do
|
||||
if teacher.ready_for_session
|
||||
if user.ready_for_session_at
|
||||
span do
|
||||
'YES'
|
||||
end
|
||||
|
|
@ -80,166 +38,22 @@ ActiveAdmin.register JamRuby::User, :as => 'Students' do
|
|||
br
|
||||
end
|
||||
span do
|
||||
link_to("mark as checked", mark_session_ready_admin_teacher_path(teacher.id), {confirm: "Mark as ready for session?"})
|
||||
link_to("mark as checked", mark_session_ready_admin_student_path(user.id), {confirm: "Mark as ready for session?"})
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
column "Top Teacher" do |teacher|
|
||||
div do
|
||||
if teacher.top_rated
|
||||
span do
|
||||
'YES'
|
||||
end
|
||||
span do
|
||||
br
|
||||
end
|
||||
span do
|
||||
link_to("mark not top", mark_not_top_admin_teacher_path(teacher.id), {confirm: "Mark as not top rated?"})
|
||||
end
|
||||
else
|
||||
span do
|
||||
'NO'
|
||||
end
|
||||
span do
|
||||
br
|
||||
end
|
||||
span do
|
||||
link_to("mark as top", mark_top_admin_teacher_path(teacher.id), {confirm: "Mark as top rated?"})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
show do
|
||||
attributes_table do
|
||||
row "Name" do |teacher|
|
||||
link_to teacher.user.name, "#{Rails.application.config.external_root_url}/client#/profile/teacher/#{teacher.user.id}"
|
||||
end
|
||||
row "Email" do |teacher|
|
||||
teacher.user.email
|
||||
end
|
||||
row "Location" do |teacher|
|
||||
teacher.user.location(country = true)
|
||||
end
|
||||
row "Profile %" do |teacher|
|
||||
div do
|
||||
span do
|
||||
"#{teacher.pct_complete[:pct]}%"
|
||||
end
|
||||
br
|
||||
br
|
||||
div do
|
||||
h5 do "Completed Sections" end
|
||||
teacher.pct_complete.each do |k, v|
|
||||
if k != :pct && v
|
||||
div do
|
||||
k
|
||||
end
|
||||
end
|
||||
end
|
||||
br
|
||||
br
|
||||
h5 do "Uncompleted Sections" end
|
||||
teacher.pct_complete.each do |k, v|
|
||||
if k != :pct && !v
|
||||
div do
|
||||
k
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
row "Background Check" do |teacher|
|
||||
div do
|
||||
if teacher.background_check_at
|
||||
span do
|
||||
teacher.background_check_at.to_date
|
||||
end
|
||||
span do
|
||||
br
|
||||
end
|
||||
span do
|
||||
link_to(mark_background_check_admin_teacher_path(teacher.id), {confirm: "Mark as background checked?"}) do
|
||||
"mark as checked"
|
||||
end
|
||||
end
|
||||
|
||||
else
|
||||
span do
|
||||
'NOT DONE'
|
||||
end
|
||||
span do
|
||||
br
|
||||
end
|
||||
span do
|
||||
link_to("mark as checked", mark_background_check_admin_teacher_path(teacher.id), {confirm: "Mark as background checked?"})
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
row "Session Ready" do |teacher|
|
||||
div do
|
||||
if teacher.ready_for_session
|
||||
span do
|
||||
'YES'
|
||||
end
|
||||
else
|
||||
span do
|
||||
'NO'
|
||||
end
|
||||
span do
|
||||
br
|
||||
end
|
||||
span do
|
||||
link_to("mark as checked", mark_session_ready_admin_teacher_path(teacher.id), {confirm: "Mark as ready for session?"})
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
row "Top Teacher" do |teacher|
|
||||
div do
|
||||
if teacher.top_rated
|
||||
span do
|
||||
'YES'
|
||||
end
|
||||
span do
|
||||
br
|
||||
end
|
||||
span do
|
||||
link_to("mark not top", mark_not_top_admin_teacher_path(teacher.id), {confirm: "Mark as not top rated?"})
|
||||
end
|
||||
else
|
||||
span do
|
||||
'NO'
|
||||
end
|
||||
span do
|
||||
br
|
||||
end
|
||||
span do
|
||||
link_to("mark as top", mark_top_admin_teacher_path(teacher.id), {confirm: "Mark as top rated?"})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
column "School" do |user|
|
||||
if teacher.school
|
||||
teacher.school.name
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
member_action :mark_session_ready, :method => :get do
|
||||
resource.mark_session_ready
|
||||
redirect_to :back
|
||||
end
|
||||
|
||||
end
|
||||
=end
|
||||
end
|
||||
|
|
@ -45,6 +45,7 @@ ActiveAdmin.register JamRuby::Teacher, :as => 'Teachers' do
|
|||
end
|
||||
|
||||
end
|
||||
=begin
|
||||
column "Background Check" do |teacher|
|
||||
div do
|
||||
if teacher.background_check_at
|
||||
|
|
@ -73,6 +74,7 @@ ActiveAdmin.register JamRuby::Teacher, :as => 'Teachers' do
|
|||
end
|
||||
end
|
||||
end
|
||||
=end
|
||||
column "Session Ready" do |teacher|
|
||||
div do
|
||||
if teacher.ready_for_session_at
|
||||
|
|
@ -122,7 +124,11 @@ ActiveAdmin.register JamRuby::Teacher, :as => 'Teachers' do
|
|||
column "Signed Up" do |teacher|
|
||||
teacher.created_at.to_date
|
||||
end
|
||||
|
||||
column "School" do |teacher|
|
||||
if teacher.school
|
||||
teacher.school.name
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
show do
|
||||
|
|
@ -166,6 +172,7 @@ ActiveAdmin.register JamRuby::Teacher, :as => 'Teachers' do
|
|||
end
|
||||
|
||||
end
|
||||
=begin
|
||||
row "Background Check" do |teacher|
|
||||
div do
|
||||
if teacher.background_check_at
|
||||
|
|
@ -196,6 +203,7 @@ ActiveAdmin.register JamRuby::Teacher, :as => 'Teachers' do
|
|||
|
||||
end
|
||||
end
|
||||
=end
|
||||
|
||||
row "Session Ready" do |teacher|
|
||||
div do
|
||||
|
|
@ -248,6 +256,12 @@ ActiveAdmin.register JamRuby::Teacher, :as => 'Teachers' do
|
|||
teacher.created_at.to_date
|
||||
end
|
||||
|
||||
row "School" do |teacher|
|
||||
if teacher.school
|
||||
teacher.school.name
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
class ApplicationController < ActionController::Base
|
||||
include ApplicationHelper
|
||||
|
||||
protect_from_forgery
|
||||
|
||||
before_filter :prepare_gon
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
module ApplicationHelper
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -340,4 +340,5 @@ jamblaster_pairing_active.sql
|
|||
email_blacklist.sql
|
||||
jamblaster_connection.sql
|
||||
teacher_progression.sql
|
||||
teacher_complete.sql
|
||||
teacher_complete.sql
|
||||
lessons.sql
|
||||
|
|
@ -0,0 +1,261 @@
|
|||
|
||||
CREATE TABLE lesson_package_types (
|
||||
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
name VARCHAR NOT NULL,
|
||||
description VARCHAR NOT NULL,
|
||||
package_type VARCHAR(64) NOT NULL,
|
||||
price NUMERIC(8,2),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE lesson_bookings (
|
||||
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
user_id VARCHAR(64) REFERENCES users(id) NOT NULL,
|
||||
active BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
accepter_id VARCHAR(64) REFERENCES users(id),
|
||||
canceler_id VARCHAR(64) REFERENCES users(id),
|
||||
lesson_type VARCHAR(64) NOT NULL,
|
||||
recurring BOOLEAN NOT NULL,
|
||||
lesson_length INTEGER NOT NULL,
|
||||
payment_style VARCHAR(64) NOT NULL,
|
||||
description VARCHAR,
|
||||
booked_price NUMERIC(8,2) NOT NULL,
|
||||
teacher_id VARCHAR(64) REFERENCES users(id) NOT NULL,
|
||||
card_presumed_ok BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
sent_notices BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
status VARCHAR,
|
||||
cancel_message VARCHAR,
|
||||
user_decremented BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE charges (
|
||||
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
amount_in_cents INTEGER NOT NULL,
|
||||
fee_in_cents INTEGER NOT NULL DEFAULT 0,
|
||||
type VARCHAR(64) NOT NULL,
|
||||
sent_billing_notices BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
sent_billing_notices_at TIMESTAMP,
|
||||
last_billing_attempt_at TIMESTAMP,
|
||||
billed BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
billed_at TIMESTAMP,
|
||||
post_processed BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
post_processed_at TIMESTAMP,
|
||||
billing_error_reason VARCHAR,
|
||||
billing_error_detail VARCHAR,
|
||||
billing_should_retry BOOLEAN NOT NULL DEFAULT TRUE ,
|
||||
billing_attempts INTEGER NOT NULL DEFAULT 0,
|
||||
stripe_charge_id VARCHAR(200),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE lesson_package_purchases (
|
||||
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
lesson_package_type_id VARCHAR(64) REFERENCES lesson_package_types(id) NOT NULL,
|
||||
user_id VARCHAR(64) REFERENCES users(id) NOT NULL,
|
||||
teacher_id VARCHAR(64) REFERENCES users(id),
|
||||
price NUMERIC(8,2),
|
||||
recurring BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
year INTEGER,
|
||||
month INTEGER,
|
||||
charge_id VARCHAR(64) REFERENCES charges(id),
|
||||
lesson_booking_id VARCHAR(64) REFERENCES lesson_bookings(id),
|
||||
sent_notices BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
sent_notices_at TIMESTAMP,
|
||||
post_processed BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
post_processed_at TIMESTAMP,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
|
||||
CREATE TABLE lesson_sessions (
|
||||
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
lesson_type VARCHAR(64) NOT NULL,
|
||||
teacher_id VARCHAR(64) REFERENCES users(id) NOT NULL,
|
||||
lesson_package_purchase_id VARCHAR(64) REFERENCES lesson_package_purchases(id),
|
||||
lesson_booking_id VARCHAR(64) REFERENCES lesson_bookings(id),
|
||||
duration INTEGER NOT NULL,
|
||||
booked_price NUMERIC(8,2) NOT NULL,
|
||||
teacher_complete BOOLEAN DEFAULT FALSE NOT NULL,
|
||||
student_complete BOOLEAN DEFAULT FALSE NOT NULL,
|
||||
student_canceled BOOLEAN DEFAULT FALSE NOT NULL,
|
||||
teacher_canceled BOOLEAN DEFAULT FALSE NOT NULL,
|
||||
student_canceled_at TIMESTAMP,
|
||||
teacher_canceled_at TIMESTAMP,
|
||||
student_canceled_reason VARCHAR,
|
||||
teacher_canceled_reason VARCHAR,
|
||||
status VARCHAR,
|
||||
analysed BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
analysis JSON,
|
||||
analysed_at TIMESTAMP,
|
||||
cancel_message VARCHAR,
|
||||
canceler_id VARCHAR(64) REFERENCES users(id),
|
||||
charge_id VARCHAR(64) REFERENCES charges(id),
|
||||
success BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
sent_notices BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
sent_notices_at TIMESTAMP,
|
||||
post_processed BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
post_processed_at TIMESTAMP,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE music_sessions ADD COLUMN lesson_session_id VARCHAR(64) REFERENCES lesson_sessions(id);
|
||||
ALTER TABLE notifications ADD COLUMN lesson_session_id VARCHAR(64) REFERENCES lesson_sessions(id);
|
||||
ALTER TABLE notifications ADD COLUMN purpose VARCHAR(200);
|
||||
ALTER TABLE notifications ADD COLUMN student_directed BOOLEAN;
|
||||
|
||||
INSERT INTO lesson_package_types (id, name, description, package_type, price) VALUES ('single', 'Single Lesson', 'A single lesson purchased at the teacher''s price.', 'single', 0.00);
|
||||
INSERT INTO lesson_package_types (id, name, description, package_type, price) VALUES ('single-free', 'Free Lesson', 'A free, single lesson.', 'single-free', 0.00);
|
||||
INSERT INTO lesson_package_types (id, name, description, package_type, price) VALUES ('test-drive', 'Test Drive', 'Four reduced-price lessons which you can use to find that ideal teacher.', 'test-drive', 49.99);
|
||||
|
||||
|
||||
CREATE TABLE lesson_booking_slots (
|
||||
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
lesson_booking_id VARCHAR(64) REFERENCES lesson_bookings(id),
|
||||
lesson_session_id VARCHAR(64) REFERENCES lesson_sessions(id),
|
||||
slot_type VARCHAR(64) NOT NULL,
|
||||
preferred_day DATE,
|
||||
day_of_week INTEGER,
|
||||
hour INTEGER,
|
||||
minute INTEGER,
|
||||
timezone VARCHAR NOT NULL,
|
||||
message VARCHAR,
|
||||
accept_message VARCHAR,
|
||||
update_all BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
proposer_id VARCHAR(64) REFERENCES users(id) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
ALTER TABLE lesson_bookings ADD COLUMN default_slot_id VARCHAR(64) REFERENCES lesson_booking_slots(id);
|
||||
ALTER TABLE lesson_bookings ADD COLUMN counter_slot_id VARCHAR(64) REFERENCES lesson_booking_slots(id);
|
||||
ALTER TABLE lesson_sessions ADD COLUMN counter_slot_id VARCHAR(64) REFERENCES lesson_booking_slots(id);
|
||||
ALTER TABLE lesson_sessions ADD COLUMN slot_id VARCHAR(64) REFERENCES lesson_booking_slots(id);
|
||||
|
||||
ALTER TABLE chat_messages ADD COLUMN target_user_id VARCHAR(64) REFERENCES users(id);
|
||||
ALTER TABLE chat_messages ADD COLUMN lesson_booking_id VARCHAR(64) REFERENCES lesson_bookings(id);
|
||||
ALTER TABLE users ADD COLUMN remaining_free_lessons INTEGER NOT NULL DEFAULT 1;
|
||||
ALTER TABLE users ADD COLUMN stored_credit_card BOOLEAN NOT NULL DEFAULT FALSE;
|
||||
ALTER TABLE users ADD COLUMN remaining_test_drives INTEGER NOT NULL DEFAULT 0;
|
||||
ALTER TABLE users ADD COLUMN stripe_token VARCHAR(200);
|
||||
ALTER TABLE users ADD COLUMN stripe_customer_id VARCHAR(200);
|
||||
ALTER TABLE users ADD COLUMN stripe_zip_code VARCHAR(200);
|
||||
ALTER TABLE sales ADD COLUMN stripe_charge_id VARCHAR(200);
|
||||
ALTER TABLE teachers ADD COLUMN stripe_account_id VARCHAR(200);
|
||||
ALTER TABLE sale_line_items ADD COLUMN lesson_package_purchase_id VARCHAR(64) REFERENCES lesson_package_purchases(id);
|
||||
|
||||
|
||||
-- one is created every time the teacher is paid. N teacher_distributions point to this
|
||||
CREATE TABLE teacher_payments (
|
||||
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
teacher_id VARCHAR(64) REFERENCES users(id) NOT NULL,
|
||||
charge_id VARCHAR(64) REFERENCES charges(id) NOT NULL,
|
||||
amount_in_cents INTEGER NOT NULL,
|
||||
fee_in_cents INTEGER NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- one is created for every bit of money the teacher is due
|
||||
CREATE TABLE teacher_distributions (
|
||||
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
teacher_id VARCHAR(64) REFERENCES users(id) NOT NULL,
|
||||
teacher_payment_id VARCHAR(64) REFERENCES teacher_payments(id),
|
||||
lesson_session_id VARCHAR(64) REFERENCES lesson_sessions(id),
|
||||
lesson_package_purchase_id VARCHAR(64) REFERENCES lesson_package_purchases(id),
|
||||
amount_in_cents INTEGER NOT NULL,
|
||||
ready BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
distributed BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE affiliate_distributions (
|
||||
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
affiliate_referral_id INTEGER REFERENCES affiliate_partners(id) NOT NULL,
|
||||
affiliate_referral_fee_in_cents INTEGER NOT NULL,
|
||||
sale_line_item_id VARCHAR(64) REFERENCES sale_line_items(id) NOT NULL,
|
||||
affiliate_refunded BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
affiliate_refunded_at TIMESTAMP WITHOUT TIME ZONE,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
ALTER TABLE affiliate_partners ADD COLUMN lesson_rate NUMERIC (8,2) NOT NULL DEFAULT 0.20;
|
||||
|
||||
-- move over all sale_line_item affiliate info
|
||||
INSERT INTO affiliate_distributions (
|
||||
SELECT
|
||||
sale_line_items.id,
|
||||
sale_line_items.affiliate_referral_id,
|
||||
sale_line_items.affiliate_referral_fee_in_cents,
|
||||
sale_line_items.id,
|
||||
sale_line_items.affiliate_refunded,
|
||||
sale_line_items.affiliate_refunded_at,
|
||||
sale_line_items.created_at,
|
||||
sale_line_items.updated_at
|
||||
FROM sale_line_items
|
||||
WHERE sale_line_items.affiliate_referral_id IS NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE teacher_intents (
|
||||
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
user_id VARCHAR(64) REFERENCES users(id) NOT NULL,
|
||||
teacher_id VARCHAR(64) REFERENCES teachers(id) NOT NULL,
|
||||
intent VARCHAR(64),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
CREATE INDEX teacher_intents_intent_idx ON teacher_intents(teacher_id, intent);
|
||||
|
||||
CREATE TABLE schools (
|
||||
id INTEGER PRIMARY KEY,
|
||||
user_id VARCHAR(64) REFERENCES users(id) NOT NULL,
|
||||
name VARCHAR,
|
||||
enabled BOOLEAN DEFAULT TRUE,
|
||||
scheduling_communication VARCHAR NOT NULL DEFAULT 'teacher',
|
||||
correspondence_email VARCHAR,
|
||||
photo_url VARCHAR(2048),
|
||||
original_fpfile VARCHAR(8000),
|
||||
cropped_fpfile VARCHAR(8000),
|
||||
cropped_s3_path VARCHAR(8000),
|
||||
crop_selection VARCHAR(256),
|
||||
large_photo_url VARCHAR(512),
|
||||
cropped_large_s3_path VARCHAR(512),
|
||||
cropped_large_fpfile VARCHAR(8000),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE SEQUENCE school_key_sequence;
|
||||
ALTER SEQUENCE school_key_sequence RESTART WITH 10000;
|
||||
ALTER TABLE schools ALTER COLUMN id SET DEFAULT nextval('school_key_sequence');
|
||||
|
||||
ALTER TABLE users ADD COLUMN school_id INTEGER REFERENCES schools(id);
|
||||
ALTER TABLE users ADD COLUMN joined_school_at TIMESTAMP;
|
||||
ALTER TABLE teachers ADD COLUMN school_id INTEGER REFERENCES schools(id);
|
||||
ALTER TABLE teachers ADD COLUMN joined_school_at TIMESTAMP;
|
||||
|
||||
CREATE TABLE school_invitations (
|
||||
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
user_id VARCHAR(64) REFERENCES users(id),
|
||||
school_id INTEGER REFERENCES schools(id) NOT NULL,
|
||||
invitation_code VARCHAR(256) NOT NULL UNIQUE,
|
||||
note VARCHAR,
|
||||
as_teacher BOOLEAN NOT NULL,
|
||||
email VARCHAR NOT NULL,
|
||||
first_name VARCHAR,
|
||||
last_name VARCHAR,
|
||||
accepted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
ALTER TABLE teachers ADD jamkazam_rate NUMERIC (8, 2) DEFAULT 0.25;
|
||||
ALTER TABLE schools ADD jamkazam_rate NUMERIC (8, 2) DEFAULT 0.25;
|
||||
|
|
@ -92,6 +92,9 @@ message ClientMessage {
|
|||
MIXDOWN_SIGN_COMPLETE = 270;
|
||||
MIXDOWN_SIGN_FAILED = 271;
|
||||
|
||||
LESSON_MESSAGE = 280;
|
||||
SCHEDULED_JAMCLASS_INVITATION = 281;
|
||||
|
||||
TEST_SESSION_MESSAGE = 295;
|
||||
|
||||
PING_REQUEST = 300;
|
||||
|
|
@ -211,6 +214,9 @@ message ClientMessage {
|
|||
optional MixdownSignComplete mixdown_sign_complete = 270;
|
||||
optional MixdownSignFailed mixdown_sign_failed = 271;
|
||||
|
||||
// lesson notifications
|
||||
optional LessonMessage lesson_message = 280;
|
||||
optional ScheduledJamclassInvitation scheduled_jamclass_invitation = 281;
|
||||
|
||||
// Client-Session messages (to/from)
|
||||
optional TestSessionMessage test_session_message = 295;
|
||||
|
|
@ -678,6 +684,31 @@ message MixdownSignFailed {
|
|||
required string mixdown_package_id = 1; // jam track mixdown package id
|
||||
}
|
||||
|
||||
message LessonMessage {
|
||||
optional string music_session_id = 1;
|
||||
optional string photo_url = 2;
|
||||
optional string msg = 3;
|
||||
optional string notification_id = 4;
|
||||
optional string created_at = 5;
|
||||
optional string sender_id = 6;
|
||||
optional string receiver_id = 7;
|
||||
optional bool student_directed = 8;
|
||||
optional string purpose = 9;
|
||||
optional string sender_name = 10;
|
||||
optional string lesson_session_id = 11;
|
||||
}
|
||||
|
||||
message ScheduledJamclassInvitation {
|
||||
optional string session_id = 1;
|
||||
optional string photo_url = 2;
|
||||
optional string msg = 3;
|
||||
optional string session_name = 4;
|
||||
optional string session_date = 5;
|
||||
optional string notification_id = 6;
|
||||
optional string created_at = 7;
|
||||
optional string lesson_session_id = 8;
|
||||
}
|
||||
|
||||
|
||||
message SubscriptionMessage {
|
||||
optional string type = 1; // the type of the subscription
|
||||
|
|
|
|||
|
|
@ -52,6 +52,10 @@ gem 'sanitize'
|
|||
gem 'influxdb', '0.1.8'
|
||||
gem 'recurly'
|
||||
gem 'sendgrid_toolkit', '>= 1.1.1'
|
||||
gem 'stripe'
|
||||
gem 'zip-codes'
|
||||
gem 'icalendar'
|
||||
gem 'email_validator'
|
||||
|
||||
group :test do
|
||||
gem 'simplecov', '~> 0.7.1'
|
||||
|
|
@ -66,7 +70,8 @@ group :test do
|
|||
gem 'rspec-prof'
|
||||
gem 'time_difference'
|
||||
gem 'byebug'
|
||||
gem 'icalendar'
|
||||
gem 'stripe-ruby-mock'
|
||||
|
||||
end
|
||||
|
||||
# Specify your gem's dependencies in jam_ruby.gemspec
|
||||
|
|
|
|||
|
|
@ -21,6 +21,9 @@ require 'rest-client'
|
|||
require 'zip'
|
||||
require 'csv'
|
||||
require 'tzinfo'
|
||||
require 'stripe'
|
||||
require 'zip-codes'
|
||||
require 'email_validator'
|
||||
|
||||
require "jam_ruby/constants/limits"
|
||||
require "jam_ruby/constants/notification_types"
|
||||
|
|
@ -53,6 +56,7 @@ require "jam_ruby/resque/scheduled/cleanup_facebook_signup"
|
|||
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/daily_session_emailer"
|
||||
require "jam_ruby/resque/scheduled/new_musician_emailer"
|
||||
require "jam_ruby/resque/scheduled/music_session_reminder"
|
||||
|
|
@ -268,10 +272,27 @@ require "jam_ruby/models/gift_card"
|
|||
require "jam_ruby/models/gift_card_purchase"
|
||||
require "jam_ruby/models/gift_card_type"
|
||||
require "jam_ruby/models/jam_track_session"
|
||||
require "jam_ruby/models/lesson_package_type"
|
||||
require "jam_ruby/models/lesson_package_purchase"
|
||||
require "jam_ruby/models/lesson_session"
|
||||
require "jam_ruby/models/lesson_booking"
|
||||
require "jam_ruby/models/lesson_booking_slot"
|
||||
require "jam_ruby/models/jamblaster"
|
||||
require "jam_ruby/models/jamblaster_user"
|
||||
require "jam_ruby/models/jamblaster_pairing_request"
|
||||
require "jam_ruby/models/sale_receipt_ios"
|
||||
require "jam_ruby/models/lesson_session_analyser"
|
||||
require "jam_ruby/models/lesson_session_monthly_price"
|
||||
require "jam_ruby/models/teacher_distribution"
|
||||
require "jam_ruby/models/teacher_payment"
|
||||
require "jam_ruby/models/charge"
|
||||
require "jam_ruby/models/teacher_payment_charge"
|
||||
require "jam_ruby/models/affiliate_payment_charge"
|
||||
require "jam_ruby/models/lesson_payment_charge"
|
||||
require "jam_ruby/models/affiliate_distribution"
|
||||
require "jam_ruby/models/teacher_intent"
|
||||
require "jam_ruby/models/school"
|
||||
require "jam_ruby/models/school_invitation"
|
||||
|
||||
include Jampb
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,16 @@
|
|||
<% provide(:title, @subject) %>
|
||||
|
||||
Hello <%= @school_invitation.first_name %> -
|
||||
<p><%= @school.owner.first_name %> is using JamKazam to deliver online music lessons, and has sent you this invitation so that you can
|
||||
register to take online music lessons with <%= @school.name %>. To accept this invitation, please click the SIGN UP NOW
|
||||
button below, and follow the instructions on the web page to which you are taken. Thanks, and on behalf of
|
||||
<%= @school.name %>, welcome to JamKazam!</p>
|
||||
<br/>
|
||||
<p>
|
||||
<a href="<%= @school_invitation.generate_signup_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;">SIGN
|
||||
UP NOW</a>
|
||||
</p>
|
||||
<br/>
|
||||
<br/>
|
||||
Best Regards,<br>
|
||||
Team JamKazam
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<% provide(:title, @subject) %>
|
||||
|
||||
Hello <%= @school_invitation.first_name %> -
|
||||
<%= @school.owner.first_name %> is using JamKazam to deliver online music lessons, and has sent you this invitation so that you can
|
||||
register to take online music lessons with <%= @school.name %>. To accept this invitation, please click the link
|
||||
below, and follow the instructions on the web page to which you are taken. Thanks, and on behalf of
|
||||
<%= @school.name %>, welcome to JamKazam!
|
||||
|
||||
<%= @school_invitation.generate_signup_url %>
|
||||
|
||||
Best Regards,<br>
|
||||
Team JamKazam
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
<% provide(:title, @subject) %>
|
||||
|
||||
Hello <%= @school_invitation.first_name %> -
|
||||
<br/>
|
||||
<p>
|
||||
<%= @school.owner.first_name %> has set up <%= @school.name %> on JamKazam, enabling you to deliver online music
|
||||
lessons in an amazing new way that really works. To accept this invitation, please click the SIGN UP NOW button below,
|
||||
and follow the instructions on the web page to which you are taken. Thanks, and welcome to JamKazam!</p>
|
||||
<br/>
|
||||
<p>
|
||||
<a href="<%= @school_invitation.generate_signup_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;">SIGN
|
||||
UP NOW</a>
|
||||
</p>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
Best Regards,<br>
|
||||
Team JamKazam
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<% provide(:title, @subject) %>
|
||||
|
||||
Hello <%= @school_invitation.first_name %> -
|
||||
<%= @school.owner.first_name %> has set up <%= @school.name %> on JamKazam, enabling you to deliver online music
|
||||
lessons in an amazing new way that really works. To accept this invitation, please click the link below,
|
||||
and follow the instructions on the web page to which you are taken. Thanks, and welcome to JamKazam!
|
||||
|
||||
<%= @school_invitation.generate_signup_url %>
|
||||
|
||||
Best Regards,
|
||||
Team JamKazam
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<% provide(:title, "Your JamClass lesson today with #{@teacher.first_name}") %>
|
||||
<% provide(:photo_url, @teacher.resolved_photo_url) %>
|
||||
|
||||
<% content_for :note do %>
|
||||
<p>
|
||||
Hello <%= @student.name %>,
|
||||
</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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<% if !@student.has_rated_teacher(@teacher) %>
|
||||
If you haven't already done so, please <a href="<%= @teacher.ratings_url %>" style="color:#fc0">rate your teacher</a> now to help other students in the community find the best
|
||||
instructors.
|
||||
<% 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>
|
||||
<br/>
|
||||
<p>
|
||||
Best Regards,<br>Team JamKazam
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<% provide(:title, "Your JamClass lesson today with #{@teacher.first_name}") %>
|
||||
<% provide(:photo_url, @teacher.resolved_photo_url) %>
|
||||
|
||||
<% content_for :note do %>
|
||||
<p>
|
||||
Hello <%= @student.name %>,
|
||||
</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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<% if !@student.has_rated_teacher(@teacher) %>
|
||||
If you haven't already done so, please <a href="<%= @teacher.ratings_url %>" style="color:#fc0">rate your teacher</a> now to help other students in the community find the best
|
||||
instructors.
|
||||
<% 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>
|
||||
<br/>
|
||||
<p>
|
||||
Best Regards,<br>Team JamKazam
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
<% provide(:title, "Your lesson 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 will not be billed for today's session with <%= @teacher.name %>. However, you already paid for the lesson in advance, so next month's bill will be lower than usual.
|
||||
<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 will not be billed for today's session with <%= @teacher.name %>. However, you already paid for the lesson in advance, so next month's bill will be lower than usual.
|
||||
|
||||
To see this lesson, click here: <%= @lesson_session.web_url %>
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
<% provide(:title, @subject) %>
|
||||
<% provide(:photo_url, @lesson_session.teacher.resolved_photo_url) %>
|
||||
|
||||
<% content_for :note do %>
|
||||
<p>
|
||||
<% if @slot.is_teacher_approved? %>
|
||||
This teacher has accepted your lesson request!
|
||||
<% else %>
|
||||
You have confirmed a lesson request.
|
||||
<% end %>
|
||||
|
||||
<% if @message.present? %>
|
||||
<br/><br/><%= @sender.name %> says:
|
||||
<br/><%= @message %>
|
||||
<br/>
|
||||
<% end %>
|
||||
<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>
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<%= @subject %>
|
||||
|
||||
To see this lesson, click here: <%= @lesson_session.web_url %>
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
<% provide(:title, @subject) %>
|
||||
<% provide(:photo_url, @lesson_booking.canceler.resolved_photo_url) %>
|
||||
|
||||
<% content_for :note do %>
|
||||
<p>
|
||||
<% if @lesson_booking.recurring %>
|
||||
|
||||
All lessons that were scheduled for <%= @lesson_booking.dayWeekDesc %> with <%= @teacher.name %> have been canceled.
|
||||
|
||||
<% else %>
|
||||
Your lesson with <%= @teacher.name %> has been canceled.<br/><br/>
|
||||
|
||||
Session Name: <%= @session_name %><br/>
|
||||
Session Description: <%= @session_description %></br>
|
||||
<%= @session_date %>
|
||||
<% end %>
|
||||
|
||||
<% if @message.present? %>
|
||||
<br/><br/><%= @lesson_booking.canceler.name %> says:
|
||||
<br/><%= @message %>
|
||||
<br/>
|
||||
<% end %>
|
||||
<br/><br/>Click the button below to view more info about the canceled 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>
|
||||
<% end %>
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<%= @subject %>
|
||||
|
||||
To see this lesson, click here: <%= @lesson_session.web_url %>
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<% provide(:title, @subject) %>
|
||||
<% provide(:photo_url, @teacher.resolved_photo_url) %>
|
||||
|
||||
<% content_for :note do %>
|
||||
<p>
|
||||
|
||||
This teacher has declined your lesson request.
|
||||
|
||||
<% if @message.present? %>
|
||||
<br/><br/><%= @teacher.name %> says:
|
||||
<br/><%= @message %>
|
||||
<br/>
|
||||
<% end %>
|
||||
<br/><br/>Click the button below to view the teacher's response.</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 RESPONSE</a>
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<%= @subject %>
|
||||
|
||||
To see this lesson, click here: <%= @lesson_session.web_url %>
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
<% provide(:title, @subject) %>
|
||||
<% provide(:photo_url, @lesson_session.canceler.resolved_photo_url) %>
|
||||
|
||||
<% content_for :note do %>
|
||||
<p>
|
||||
Your lesson with <%= @teacher.name %> has been canceled.<br/><br/>
|
||||
|
||||
Session Name: <%= @session_name %><br/>
|
||||
Session Description: <%= @session_description %></br>
|
||||
<%= @session_date %>
|
||||
|
||||
<% if @message.present? %>
|
||||
<br/><br/><%= @lesson_session.canceler.name %> says:
|
||||
<br/><%= @message %>
|
||||
<br/>
|
||||
<% end %>
|
||||
<br/><br/>Click the button below to view more info about the canceled 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 RESPONSE</a>
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<%= @subject %>
|
||||
|
||||
To see this lesson, click here: <%= @lesson_session.web_url %>
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<% provide(:title, "#{@teacher.name} has proposed a different time for your lesson") %>
|
||||
<% provide(:photo_url, @teacher.resolved_photo_url) %>
|
||||
|
||||
<% content_for :note do %>
|
||||
<p>
|
||||
<%= @teacher.name %> has proposed a different time for your lesson request.
|
||||
<br/>
|
||||
<br/>
|
||||
Click the button below to get more information and respond.
|
||||
</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>
|
||||
<% end %>
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<%= @teacher.name %> has proposed a different time for your lesson request.
|
||||
|
||||
To see this lesson, click here: <%= @lesson_session.web_url %>
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<% provide(:title, @subject) %>
|
||||
<% provide(:photo_url, @teacher.resolved_photo_url) %>
|
||||
|
||||
<% content_for :note do %>
|
||||
<p>
|
||||
Hello <%= @student.name %>,
|
||||
</p>
|
||||
|
||||
<p>
|
||||
You have been billed $<%= @lesson_package_purchase.amount_charged %> for this month's lessons with <%= @teacher.name %>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<% if !@student.has_rated_teacher(@teacher) %>
|
||||
If you haven't already done so, please <a href="<%= @teacher.ratings_url %>" style="color:#fc0">rate your teacher</a> now to help other students in the community find the best
|
||||
instructors.
|
||||
<% 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>
|
||||
<br/>
|
||||
<p>
|
||||
Best Regards,<br>Team JamKazam
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
Hello <%= @student.name %>,
|
||||
|
||||
You have been billed $<%= @lesson_package_purchase.amount_charged %> for this month's lessons with <%= @teacher.name %>.
|
||||
|
||||
<% if !@student.has_rated_teacher(@teacher) %>
|
||||
If you haven't already done so, please rate your teachernow to help other students in the community find the best instructors. <%= @teacher.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.
|
||||
|
||||
Best Regards,
|
||||
Team JamKazam
|
||||
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<% provide(:title, @subject) %>
|
||||
<% provide(:photo_url, @teacher.resolved_photo_url) %>
|
||||
|
||||
<% content_for :note do %>
|
||||
<p>
|
||||
Hello <%= @student.name %>,
|
||||
</p>
|
||||
|
||||
<p>
|
||||
You have been billed $<%= @lesson_package_purchase.amount_charged %> for this month's lessons with <%= @teacher.name %>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<% if !@student.has_rated_teacher(@teacher) %>
|
||||
If you haven't already done so, please <a href="<%= @teacher.ratings_url %>" style="color:#fc0">rate your teacher</a> now to help other students in the community find the best
|
||||
instructors.
|
||||
<% 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>
|
||||
<br/>
|
||||
<p>
|
||||
Best Regards,<br>Team JamKazam
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
<% provide(:title, "Your JamClass lesson today with #{@teacher.first_name}") %>
|
||||
<% provide(:photo_url, @teacher.resolved_photo_url) %>
|
||||
|
||||
<% content_for :note do %>
|
||||
<p>
|
||||
Hello <%= @student.name %>,
|
||||
</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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<% if !@student.has_rated_teacher(@teacher) %>
|
||||
If you haven't already done so, please <a href="<%= @teacher.ratings_url %>" style="color:#fc0">rate your teacher</a> now to help other students in the community find the best
|
||||
instructors.
|
||||
<% 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>
|
||||
<br/>
|
||||
<p>
|
||||
Best Regards,<br>Team JamKazam
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
Hello <%= @student.name %>,
|
||||
|
||||
We hope you enjoyed your JamClass lesson today with <%= @teacher.name %>. You have been billed $<%= @lesson_session.amount_charged %> for today's lesson.
|
||||
|
||||
<% if !@student.has_rated_teacher(@teacher) %>
|
||||
If you haven't already done so, please rate your teacher now to help other students in the community find the best
|
||||
instructors. You can rate your teacher here: <%= @teacher.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.
|
||||
|
||||
Best Regards,
|
||||
Team JamKazam
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
<% provide(:title, "Your lesson 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 will not be billed for today's session 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 will not be billed for today's session with <%= @teacher.name %>
|
||||
|
||||
To see this lesson, click here: <%= @lesson_session.web_url %>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<% provide(:title, "Lesson requested of #{@sender.name}") %>
|
||||
<% provide(:photo_url, @sender.resolved_photo_url) %>
|
||||
|
||||
<% content_for :note do %>
|
||||
<p>You have requested a <%= @lesson_booking.display_type %> lesson. <br /><br/>Click the button below to see your lesson request. You will receive another email when the teacher accepts or rejects the request.</p>
|
||||
<p>
|
||||
<a href="<%= @lesson_booking.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 REQUEST</a>
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
You have requested a lesson from <%= @sender.name %>.
|
||||
|
||||
To see this lesson request, click here: <%= @lesson_booking.web_url %>
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<% provide(:title, @subject) %>
|
||||
<% provide(:photo_url, @lesson_session.teacher.resolved_photo_url) %>
|
||||
|
||||
<% content_for :note do %>
|
||||
<p>
|
||||
All lessons with <%= @lesson_session.teacher.name %> have been rescheduled.
|
||||
|
||||
<% if @message.present? %>
|
||||
<br/><br/><%= @sender.name %> says:
|
||||
<br/><%= @message %>
|
||||
<br/>
|
||||
<% end %>
|
||||
<br/><br/>Click the button below to get more information and to update 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>
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
All your lessons with <%= @lesson_session.teacher.name%> have been rescheduled.
|
||||
|
||||
To see this lesson, click here: <%= @lesson_session.web_url %>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<% provide(:title, @subject) %>
|
||||
|
||||
<p><%= @body %></p>
|
||||
|
||||
<p>
|
||||
Session Name: <%= @session_name %><br/>
|
||||
<%= @session_description %></br>
|
||||
<%= @session_date %>
|
||||
</p>
|
||||
|
||||
<p><a style="color: #ffcc00;" href="<%= @session_url %>">VIEW LESSON DETAILS</a></p>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<%= @body %>
|
||||
|
||||
<%= @session_name %>
|
||||
<%= @session_description %>
|
||||
<%= @session_date %>
|
||||
|
||||
See session details at <%= @session_url %>.
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
<% provide(:title, "You have used #{@student.remaining_test_drives} of 4 TestDrive lesson credits") %>
|
||||
<% provide(:photo_url, @teacher.resolved_photo_url) %>
|
||||
|
||||
<% content_for :note do %>
|
||||
<p>
|
||||
Hello <%= @student.name %>,
|
||||
</p>
|
||||
|
||||
<p>We hope you enjoyed your JamClass lesson today with <%= @teacher.name %>. You have
|
||||
used <%= @student.used_test_drives %> TestDrive credits, and you have <%= @student.remaining_test_drives %>
|
||||
remaining TestDrive lesson(s) available. If you haven’t booked your next TestDrive lesson,
|
||||
<a href="<%= User.search_url %>" style="color:#fc0">click here</a> to search our teachers and get your next
|
||||
lesson lined up today!</p>
|
||||
|
||||
<p>
|
||||
<% if !@student.has_rated_teacher(@teacher) %>
|
||||
Also, please <a href="<%= @teacher.ratings_url %>" style="color:#fc0">rate your teacher</a> now for today’s lesson
|
||||
to help other students in the community find the best instructors.
|
||||
<% end %>
|
||||
And 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>
|
||||
<br/>
|
||||
<p>
|
||||
Best Regards,<br>Team JamKazam
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
You have used <%= @student.remaining_test_drives %> of 4 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.
|
||||
<% end %>
|
||||
|
||||
If you clicked with one of your TestDrive instructors, here are links to each teacher’s listing. You can use the
|
||||
link to your favorite to book single or weekly recurring lessons with the best instructor for you!
|
||||
<% @student.recent_test_drive_teachers.each do |teacher| %>
|
||||
<%= teacher.name %>: <%= teacher.teacher_profile_url %>
|
||||
<% end %>
|
||||
|
||||
And 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.
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
<% provide(:title, "You have used all 4 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.
|
||||
|
||||
<% 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
|
||||
help other students in the community find the best instructors.
|
||||
<% end %>
|
||||
</p>
|
||||
<p>
|
||||
If you clicked with one of your TestDrive instructors, here are links to each teacher’s listing. You can use the
|
||||
link to your favorite to book single or weekly recurring lessons with the best instructor for you!
|
||||
</p>
|
||||
<% @student.recent_test_drive_teachers.each do |teacher| %>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td width="58" align="left" valign="top">
|
||||
<p style="padding:2px;width:54px;height:54px;background-color:#ed3618;-webkit-border-radius:28px;-moz-border-radius:28px;border-radius:28px;margin-right:10px">
|
||||
<img src="<%= teacher.resolved_photo_url %>" width="54" height="54" style="-webkit-border-radius:26px;-moz-border-radius:26px;border-radius:26px;">
|
||||
</p></td>
|
||||
<td><p>
|
||||
<font size="3" color="#AAAAAA" face="Arial, Helvetica, sans-serif"><a href="<%= teacher.teacher_profile_url %>"><%= teacher.name %></a></font>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<% end %>
|
||||
|
||||
<p>
|
||||
And 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>
|
||||
<br/>
|
||||
|
||||
<p>
|
||||
Best Regards,<br>Team JamKazam
|
||||
</p>
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
You have used all of your 4 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.
|
||||
<% end %>
|
||||
|
||||
And 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.
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<% provide(:title, "The credit card charge for your lesson today with #{@teacher.first_name} failed") %>
|
||||
<% provide(:photo_url, @teacher.resolved_photo_url) %>
|
||||
|
||||
<% content_for :note do %>
|
||||
<p>
|
||||
Hello <%= @student.name %>,
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
||||
<% if @card_declined %>
|
||||
When we tried to charge your credit card for your lesson on <%= @bill_date %> with <%= @teacher.name %>, the charge was declined. Can you please call your credit card company to clear up the issue, or if you need to update some of your credit card information, please use the button below to go to a page where you can change your card info. Thank you!
|
||||
<% elsif @card_expired %>
|
||||
When we tried to charge your credit card for your lesson on <%= @bill_date %> with <%= @teacher.name %>, the charge failed because the card is expired. To update your credit card information, please use the button below to go to a page where you can change your card info. Thank you!
|
||||
<% else %>
|
||||
For some reason, when we tried to charge your credit card for your lesson on <%= @bill_date %> with <%= @teacher.name %>, the charge failed. Can you please call your credit card company to clear up the issue, or if you need to update some of your credit card information, please use the button below to go to a page where you can change your card info. Thank you!
|
||||
<% end %>
|
||||
|
||||
</p>
|
||||
<p>
|
||||
<a href="<%= @lesson_session.update_payment_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;">UPDATE PAYMENT INFO</a>
|
||||
</p>
|
||||
<p>
|
||||
Best Regards,<br>Team JamKazam
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
The credit card charge for your lesson today with <%= @teacher.first_name %> failed.
|
||||
Hello <%= @student.name %>,
|
||||
|
||||
<% if @card_declined %>
|
||||
When we tried to charge your credit card for your lesson on <%= @bill_date %> with <%= @teacher.name %>, the charge was declined. Can you please call your credit card company to clear up the issue, or if you need to update some of your credit card information, please use the button below to go to a page where you can change your card info. Thank you!
|
||||
<% elsif @card_expired %>
|
||||
When we tried to charge your credit card for your lesson on <%= @bill_date %> with <%= @teacher.name %>, the charge failed because the card is expired. To update your credit card information, please use the button below to go to a page where you can change your card info. Thank you!
|
||||
<% else %>
|
||||
For some reason, when we tried to charge your credit card for your lesson on <%= @bill_date %> with <%= @teacher.name %>, the charge failed. Can you please call your credit card company to clear up the issue, or if you need to update some of your credit card information, please use the button below to go to a page where you can change your card info. Thank you!
|
||||
<% end %>
|
||||
|
||||
|
||||
Update Payment info here: <%= @lesson_session.update_payment_url %>
|
||||
|
||||
Best Regards,
|
||||
Team JamKazam
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
<% provide(:title, @subject) %>
|
||||
<% provide(:photo_url, @teacher.resolved_photo_url) %>
|
||||
|
||||
<% content_for :note do %>
|
||||
<p>
|
||||
Hello <%= @student.name %>,
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<% if @lesson_booking.is_suspended? %>
|
||||
Your weekly lessons with <%= @teacher.name %> have been suspended because we have tried repeatedly to charge your credit card but have failed.
|
||||
<br/>
|
||||
<br/>
|
||||
<% end %>
|
||||
|
||||
<% if @card_declined %>
|
||||
When we tried to charge your credit card for your <%= @month_name %> lessons on <%= @bill_date %> with <%= @teacher.name %>, the charge was declined. Can you please call your credit card company to clear up the issue, or if you need to update some of your credit card information, please use the button below to go to a page where you can change your card info. Thank you!
|
||||
<% elsif @card_expired %>
|
||||
When we tried to charge your credit card for your <%= @month_name %> lessons on <%= @bill_date %> with <%= @teacher.name %>, the charge failed because the card is expired. To update your credit card information, please use the button below to go to a page where you can change your card info. Thank you!
|
||||
<% else %>
|
||||
For some reason, when we tried to charge your credit card for your <%= @month_name %> lessons on <%= @bill_date %> with <%= @teacher.name %>, the charge failed. Can you please call your credit card company to clear up the issue, or if you need to update some of your credit card information, please use the button below to go to a page where you can change your card info. Thank you!
|
||||
<% end %>
|
||||
</p>
|
||||
<p>
|
||||
<a href="<%= @lesson_booking.update_payment_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;">UPDATE PAYMENT INFO</a>
|
||||
</p>
|
||||
<p>
|
||||
Best Regards,<br>Team JamKazam
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
Hello <%= @student.name %>,
|
||||
|
||||
<%= @subject %>
|
||||
|
||||
<% if @lesson_booking.is_suspended? %>
|
||||
Your weekly lessons with <%= @teacher.name %> have been suspended because we have tried repeatedly to charge your credit card but have failed.
|
||||
<% end %>
|
||||
|
||||
<% if @card_declined %>
|
||||
When we tried to charge your credit card for your <%= @month_name %> lessons on <%= @bill_date %> with <%= @teacher.name %>, the charge was declined. Can you please call your credit card company to clear up the issue, or if you need to update some of your credit card information, please use the button below to go to a page where you can change your card info. Thank you!
|
||||
<% elsif @card_expired %>
|
||||
When we tried to charge your credit card for your <%= @month_name %> lessons on <%= @bill_date %> with <%= @teacher.name %>, the charge failed because the card is expired. To update your credit card information, please use the button below to go to a page where you can change your card info. Thank you!
|
||||
<% else %>
|
||||
For some reason, when we tried to charge your credit card for your <%= @month_name %> lessons on <%= @bill_date %> with <%= @teacher.name %>, the charge failed. Can you please call your credit card company to clear up the issue, or if you need to update some of your credit card information, please use the button below to go to a page where you can change your card info. Thank you!
|
||||
<% end %>
|
||||
|
||||
|
||||
Update Payment info here: <%= @lesson_booking.update_payment_url %>
|
||||
|
||||
Best Regards,
|
||||
Team JamKazam
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
<% provide(:title, 'Welcome to JamKazam!') %>
|
||||
|
||||
|
||||
<% if !@user.anonymous? %>
|
||||
<p>Hello <%= EmailBatchProgression::VAR_FIRST_NAME %> --
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
|
||||
<p> We're delighted you have decided to join the JamKazam community of musicians, and we hope
|
||||
|
||||
you will enjoy using JamKazam and JamTracks to play more music. Following are some
|
||||
|
||||
resources and some things you can do to get the most out of JamKazam.
|
||||
</p>
|
||||
|
||||
|
||||
<p><b style="color: white;">Playing With JamTracks</b><br/>
|
||||
|
||||
JamTracks are the best way to play along with your favorite songs. Far better and different than
|
||||
|
||||
traditional backing tracks, our JamTracks are complete multi-track professional recordings, with
|
||||
|
||||
fully isolated tracks for each part of the music. And our free app and Internet service are packed
|
||||
|
||||
with features that give you unmatched creative freedom to learn, practice, record, play with
|
||||
|
||||
others, and share your performances. Here are some great JamTracks resources:
|
||||
</p>
|
||||
<ul>
|
||||
<li><a style="color:#fc0" href="https://www.youtube.com/watch?v=07zJC7C2ICA">JamTracks Overview Video</a> - See all the great things you can do with JamTracks.</li>
|
||||
<li><a style="color:#fc0" href="https://jamkazam.desk.com/customer/en/portal/articles/2124663-playing-with-jamtracks">JamTracks User Guide</a> - A set of articles that explain how to use all the JamTracks
|
||||
|
||||
features.</li>
|
||||
<li><a style="color:#fc0" href="https://www.jamkazam.com/client#/jamtrack">Get a JamTrack Free</a> - A web page you can visit to search our catalog of JamTracks.
|
||||
|
||||
When you find a song you like, click the Get It Free button, and your first one is free! If
|
||||
|
||||
you already redeemed a free JamTrack or purchased JamTracks, you can also access
|
||||
|
||||
them on this page from your web browser.</li>
|
||||
<li><a style="color:#fc0" href="https://www.jamkazam.com/downloads">JamKazam Application</a> - A web page where you can download our free Mac or Windows
|
||||
|
||||
app. The app lets you do a lot more with JamTracks than you can do in a browser.</li>
|
||||
</ul>
|
||||
|
||||
<p><b style="color: white;">Play Live With Others from Different Locations on JamKazam</b><br/>
|
||||
JamKazam’s free app lets musicians play together live and in sync from different locations over
|
||||
|
||||
the Internet. Kind of like Skype on super audio steroids, with ultra low latency and terrific audio
|
||||
|
||||
quality. You can set up online sessions that are public or private, for you alone or for others to
|
||||
|
||||
join. You can find and join others’ sessions, use backing tracks and loops in sessions, make
|
||||
|
||||
audio and video recordings of session performances, and more. <a style="color:#fc0" href="https://jamkazam.desk.com/customer/en/portal/topics/673198-tutorials-on-major-features/articles">Click here for a set of tutorial
|
||||
|
||||
videos that show how to use these features</a>.
|
||||
</p>
|
||||
|
||||
<p><b style="color: white;">Teach or Take Online Music Lessons</b><br/>
|
||||
If you teach music lessons and have tried to give lessons using Skype, you’ll know how
|
||||
|
||||
unsatisfactory that experience is. Audio quality is poor, and latency prohibits teacher and
|
||||
|
||||
student playing together at all. JamKazam is a terrific service for teaching and taking online
|
||||
|
||||
music lessons. If you want to use JamKazam for lessons, we’ll be happy to support both you and
|
||||
|
||||
your students in getting set up and ready to go.
|
||||
</p>
|
||||
|
||||
<p><b style="color: white;">Complete Your Profile</b><br/>
|
||||
Every member of our community has a profile. It’s a great way to share a little bit about who
|
||||
|
||||
you are as a musician, as well as your musical interests. For example, what instruments do you
|
||||
|
||||
play? What musical genres do you like best? Are you interested in getting into a virtual/online
|
||||
|
||||
or a real-world band? And so on. Filling out your profile will help you connect with others with
|
||||
|
||||
common interests. To do this, go to <a style="color:#fc0" href="https://www.jamkazam.com/client">www.jamkazam.com</a> or launch the JamKazam app. Then
|
||||
|
||||
click on the Profile tile, and click the Edit Profile button.
|
||||
</p>
|
||||
|
||||
<p><b style="color: white;">Invite Your Friends</b><br/>
|
||||
Have friends who are musicians? Invite them to join you to play together on JamKazam. To do
|
||||
|
||||
this, go to <a style="color:#fc0" href="https://www.jamkazam.com/client">www.jamkazam.com</a> or launch the JamKazam app. Then move your mouse over the
|
||||
|
||||
user icon in the top right corner of the screen. A menu will be displayed. Click Invite Friends in
|
||||
|
||||
this menu, and you can then use the options to invite your friends using their email addresses,
|
||||
|
||||
or via Facebook, or using your Google contacts.
|
||||
<p>
|
||||
|
||||
<p><b style="color: white;">Get Help</b><br/>
|
||||
|
||||
If you run into trouble and need help, please reach out to us. We will be glad to do everything
|
||||
|
||||
we can to answer your questions and get you up and running. You can visit our <a style="color:#fc0" href="https://jamkazam.desk.com/">Support Portal</a>
|
||||
|
||||
to find knowledge base articles and post questions that have not already been answered. You
|
||||
|
||||
can email us at <a style="color:#fc0" href="mailto:support@jamkazam.com">support@jamkazam.com</a>. And if you just want to chat, share tips and war
|
||||
|
||||
stories, and hang out with fellow JamKazamers, you can visit our <a style="color:#fc0" href="http://forums.jamkazam.com/">Community Forum</a>.
|
||||
<p>
|
||||
|
||||
<p>
|
||||
<br/>
|
||||
<br/>
|
||||
Again, welcome to JamKazam, and we hope you have a great time here!
|
||||
</p>
|
||||
|
||||
<p>Best Regards,<br/>
|
||||
Team JamKazam</p>
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
<% if !@user.anonymous? %>Hello <%= EmailBatchProgression::VAR_FIRST_NAME %> --<% end %>
|
||||
|
||||
We're delighted that you have decided to try the JamKazam service, and we hope that you will enjoy using JamKazam to play music with others. Following are some resources that can help you get oriented and get the most out of JamKazam.
|
||||
|
||||
|
||||
Getting Started
|
||||
---------------
|
||||
|
||||
There are basically three kinds of setups you can use to play on JamKazam.
|
||||
|
||||
* Built-In Audio on Your Computer - You can use a Windows or Mac computer, and just use the built-in mic and headphone jack to handle your audio. This is cheap and easy, but your audio quality will suffer, and it will also process audio very slowly, creating problems with latency, or lag, in your sessions. Still, you can at least start experimenting with JamKazam in this way.
|
||||
|
||||
* Computer with External Audio Interface - - You can use a Windows or Mac computer with an external audio interface that you already own and use for recording, if you happen to have one already. If you are going to do this, or use the built-in mic/headphones on your computer, please refer to our Minimum System Requirements at https://jamkazam.desk.com/customer/portal/articles/1288274-minimum-system-requirements to make sure your computer will work. These requirements were on the download page for the app, but you may have sped by them. Also, we'd recommend watching our Getting Started Video at https://www.youtube.com/watch?v=DBo--aj_P1w to learn more about your options here.
|
||||
|
||||
* The JamBlaster - JamKazam has designed a new product from the ground up to be the best way to play music online in real time. It's called the JamBlaster. It processes audio faster than any of the thousands of combinations of computers and interfaces in use on JamKazam today, which means you can play with musicians who are farther away from you, and closer sessions will feel/sound tighter. The JamBlaster is both a computer and an audio interface, so it also eliminates the system requirements worries, and it "just works" so you don't have to be an audio and computer genius to get it working. This is a great product - available only through a Kickstarter program running during a 30-day window during parts of February and March 2015. You can watch the JamBlaster Video at https://www.youtube.com/watch?v=gAJAIHMyois to learn more about this amazing new product.
|
||||
|
||||
|
||||
JamKazam Features
|
||||
-----------------
|
||||
|
||||
JamKazam offers a very robust and exciting set of features for playing online and sharing your performances with others. Here are some videos you can watch to easily get up to speed on some of the things you can do with JamKazam:
|
||||
|
||||
* Creating a Session - https://www.youtube.com/watch?v=EZZuGcDUoWk
|
||||
|
||||
* Finding a Session - https://www.youtube.com/watch?v=xWponSJo-GU
|
||||
|
||||
* Playing in a Session - https://www.youtube.com/watch?v=zJ68hA8-fLA
|
||||
|
||||
* Connecting with Other Musicians - https://www.youtube.com/watch?v=4KWklSZZxRc
|
||||
|
||||
* Working with Recordings - https://www.youtube.com/watch?v=Gn-dOqnNLoY
|
||||
|
||||
|
||||
Getting Help
|
||||
------------
|
||||
|
||||
If you run into trouble and need help, please reach out to us. We will be glad to do everything we can to answer your questions and get you up and running. You can visit our Support Portal at https://jamkazam.desk.com/ to find knowledge base articles and post questions that have not already been answered. You can email us at support@jamkazam.com. And if you just want to chat, share tips and war stories, and hang out with fellow JamKazamers, you can visit our Community Forum at http://forums.jamkazam.com/.
|
||||
|
||||
Again, welcome to JamKazam, and we look forward to seeing – and hearing – you online soon!
|
||||
|
||||
Best Regards,
|
||||
Team JamKazam
|
||||
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
<% provide(:title, @subject) %>
|
||||
|
||||
<p>You were paid a total of $<%= @teacher_payment.amount %> for your participation in JamClass. Below are more details:</p>
|
||||
<br/>
|
||||
|
||||
<% @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>
|
||||
<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.
|
||||
<% 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>
|
||||
<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.
|
||||
<% 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>
|
||||
<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.
|
||||
<% 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>
|
||||
<% else %>
|
||||
Unknown payment type.
|
||||
<% end %>
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<% end %>
|
||||
|
||||
Best Regards,<br/>
|
||||
JamKazam
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
<% provide(:title, @subject) %>
|
||||
|
||||
You were paid a total of $<%= @teacher_payment.amount %> for your participation in JamClass. Below are more details:
|
||||
|
||||
<% @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 %>
|
||||
<% 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 %>
|
||||
<% 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 %>
|
||||
<% 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
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<% provide(:title, @subject) %>
|
||||
|
||||
<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!
|
||||
<% elsif @card_expired %>
|
||||
When we tried to distribute a payment to you on <%= @bill_date %>, the charge was declined by stripe due to a card expiration. Can you please check your stripe account status? Thank you!
|
||||
<% 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 %>
|
||||
</p>
|
||||
<br/>
|
||||
|
||||
Best Regards,<br/>
|
||||
JamKazam
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<% provide(:title, @subject) %>
|
||||
|
||||
<% 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 %>
|
||||
When we tried to distribute a payment to you on <%= @bill_date %>, the charge was declined by stripe due to a card expiration. Can you please check your stripe account status? Thank you!
|
||||
<% 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 %>
|
||||
|
||||
Best Regards,
|
||||
JamKazam
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
<% provide(:title, @subject) %>
|
||||
<% provide(:photo_url, @lesson_session.student.resolved_photo_url) %>
|
||||
|
||||
<% content_for :note do %>
|
||||
<p>
|
||||
<% if @slot.is_teacher_approved? %>
|
||||
You have confirmed a lesson request.
|
||||
<% 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/>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>
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
You have confirmed a lesson request for <%= @sender.name %>.
|
||||
|
||||
To see this lesson, click here: <%= @lesson_session.web_url %>
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
<% provide(:title, @subject) %>
|
||||
<% provide(:photo_url, @lesson_booking.canceler.resolved_photo_url) %>
|
||||
|
||||
<% content_for :note do %>
|
||||
<p>
|
||||
<% if @lesson_booking.recurring %>
|
||||
|
||||
All lessons that were scheduled for <%= @lesson_booking.dayWeekDesc %> with <%= @student.name %> have been canceled.
|
||||
|
||||
<% else %>
|
||||
Your lesson with <%= @student.name %> has been canceled.<br/><br/>
|
||||
|
||||
Session Name: <%= @session_name %><br/>
|
||||
Session Description: <%= @session_description %></br>
|
||||
<%= @session_date %>
|
||||
<% end %>
|
||||
|
||||
<% if @message.present? %>
|
||||
<br/><br/><%= @lesson_booking.canceler.name %> says:
|
||||
<br/><%= @message %>
|
||||
<br/>
|
||||
<% end %>
|
||||
<br/><br/>Click the button below to view more info about the canceled 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>
|
||||
<% end %>
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<%= @subject %>
|
||||
|
||||
To see this lesson, click here: <%= @lesson_session.web_url %>
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
<% provide(:title, @subject) %>
|
||||
<% provide(:photo_url, @lesson_session.canceler.resolved_photo_url) %>
|
||||
|
||||
<% content_for :note do %>
|
||||
<p>
|
||||
|
||||
Your lesson with <%= @teacher.name %> has been canceled.<br/><br/>
|
||||
|
||||
Session Name: <%= @session_name %><br/>
|
||||
Session Description: <%= @session_description %></br>
|
||||
<%= @session_date %>
|
||||
|
||||
<% if @message.present? %>
|
||||
<br/><br/><%= @lesson_session.canceler.name %> says:
|
||||
<br/><%= @message %>
|
||||
<br/>
|
||||
<% end %>
|
||||
<br/><br/>Click the button below to view more info about the canceled 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>
|
||||
<% end %>
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<%= @subject %>
|
||||
|
||||
To see this lesson, click here: <%= @lesson_session.web_url %>
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<% provide(:title, "You successfully completed a lesson with #{@student.name}") %>
|
||||
<% provide(:photo_url, @student.resolved_photo_url) %>
|
||||
|
||||
<% content_for :note do %>
|
||||
<p>
|
||||
<%= @student.name %> will first be billed and you should receive your payment in the next 48 hours.
|
||||
<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>
|
||||
<% end %>
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
You successfully completed a lesson with <%= @student.name %>.
|
||||
|
||||
To see this lesson, click here: <%= @lesson_session.web_url %>
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<% provide(:title, "#{@student.name} has proposed a different time for their lesson") %>
|
||||
<% provide(:photo_url, @student.resolved_photo_url) %>
|
||||
|
||||
<% content_for :note do %>
|
||||
<p>
|
||||
<%= @student.name %> has proposed a different time for their lesson request.
|
||||
<br/>
|
||||
<br/>
|
||||
Click the button below to get more information and respond.
|
||||
</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>
|
||||
<% end %>
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<%= @student.name %> has proposed a different time for their lesson request.
|
||||
|
||||
To see this lesson, click here: <%= @lesson_session.web_url %>
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
<% provide(:title, @subject) %>
|
||||
<% provide(:photo_url, @student.resolved_photo_url) %>
|
||||
|
||||
<% content_for :note do %>
|
||||
<p>
|
||||
Hello <%= @teacher.name %>,
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Your student, <%= @student.name %>, has been billed for this month's lessons. You should receive your funds within 48 hours.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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>
|
||||
<br/>
|
||||
<p>
|
||||
Best Regards,<br>Team JamKazam
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
Hello <%= @teacher.name %>,
|
||||
|
||||
Your student, <%= @student.name %>, has been billed for this month's lessons. You should receive your funds within 48 hours.
|
||||
|
||||
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>.
|
||||
|
||||
Best Regards,
|
||||
Team JamKazam
|
||||
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
<% provide(:title, "Your JamClass lesson today with #{@student.first_name}") %>
|
||||
<% provide(:photo_url, @student.resolved_photo_url) %>
|
||||
|
||||
<% content_for :note do %>
|
||||
<p>
|
||||
Hello <%= @teacher.name %>,
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Your student <%= @student.name %> will be billed for today's lesson, and you should receive payment within 48 hours.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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>
|
||||
<br/>
|
||||
<p>
|
||||
Best Regards,<br>Team JamKazam
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
Hello <%= @teacher.name %>,
|
||||
|
||||
Your student <%= @student.name %> will be billed for today's lesson, and you will receive payment within 24 hours.
|
||||
|
||||
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.
|
||||
|
||||
Best Regards,
|
||||
Team JamKazam
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
<% provide(:title, "Your student #{@student.name} will not be charged for their lesson") %>
|
||||
<% provide(:photo_url, @student.resolved_photo_url) %>
|
||||
|
||||
<% content_for :note do %>
|
||||
<p>
|
||||
Hello <%= @teacher.name %>,
|
||||
</p>
|
||||
|
||||
<p>Your student <%= @student.name %> will not be billed for today's session.
|
||||
<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 <%= @teacher.name %>,
|
||||
|
||||
Your student <%= @student.name %> will not be billed for today's session.
|
||||
|
||||
To see this lesson, click here: <%= @lesson_session.web_url %>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<% provide(:title, "Lesson Request from #{@sender.name}") %>
|
||||
<% provide(:photo_url, @sender.resolved_photo_url) %>
|
||||
|
||||
<% content_for :note do %>
|
||||
<p>This student has requested to schedule a <%= @lesson_booking.display_type %> lesson. <br /><br/>Click the button below to get more information and to respond to this lesson request. You must respond to this lesson request promptly, or it will be cancelled, thank you!</p>
|
||||
<p>
|
||||
<a href="<%= @lesson_booking.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 REQUEST</a>
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<%= @sender.name %> has requested a lesson.
|
||||
|
||||
To see this lesson request, click here: <%= @lesson_booking.home_url %>
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<% provide(:title, @subject) %>
|
||||
<% provide(:photo_url, @lesson_session.student.resolved_photo_url) %>
|
||||
|
||||
<% content_for :note do %>
|
||||
<p>
|
||||
All lessons with <%= @lesson_session.student.name %> have been rescheduled.
|
||||
|
||||
<% if @message.present? %>
|
||||
<br/><br/><%= @sender.name %> says:
|
||||
<br/><%= @message %>
|
||||
<br/>
|
||||
<% end %>
|
||||
<br/><br/>Click the button below to get more information and to update 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>
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
All your lessons with <%= @lesson_session.student.name %> have been rescheduled.
|
||||
|
||||
To see this lesson, click here: <%= @lesson_session.web_url %>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<% provide(:title, @subject) %>
|
||||
|
||||
<p><%= @body %></p>
|
||||
|
||||
<p>
|
||||
Session Name: <%= @session_name %><br/>
|
||||
<%= @session_description %></br>
|
||||
<%= @session_date %>
|
||||
</p>
|
||||
|
||||
<p><a style="color: #ffcc00;" href="<%= @session_url %>">VIEW LESSON DETAILS</a></p>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<%= @body %>
|
||||
|
||||
<%= @session_name %>
|
||||
<%= @session_description %>
|
||||
<%= @session_date %>
|
||||
|
||||
See session details at <%= @session_url %>.
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
<% provide(:title, @subject) %>
|
||||
<% provide(:photo_url, @student.resolved_photo_url) %>
|
||||
|
||||
<% content_for :note do %>
|
||||
<p>
|
||||
Hello <%= @teacher.name %>,
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<% if @lesson_booking.is_suspended? %>
|
||||
Your weekly lessons with <%= @student.name %> have been suspended because we have tried repeatedly to charge their credit card but the charge was declined. They have been asked to re-enter updated credit card info.
|
||||
<% else %>
|
||||
We have tried to charge the credit card of <%= @student.name %> but the charge was declined. They still have time to re-enter their credit card info before the session is suspended, though.
|
||||
<% end %>
|
||||
</p>
|
||||
<p>
|
||||
Best Regards,<br>Team JamKazam
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
Hello <%= @student.name %>,
|
||||
|
||||
<%= @subject %>
|
||||
|
||||
<% if @lesson_booking.is_suspended? %>
|
||||
Your weekly lessons with <%= @student.name %> have been suspended because we have tried repeatedly to charge their credit card but the charge was declined. They have been asked to re-enter updated credit card info.
|
||||
<% else %>
|
||||
We have tried to charge the credit card of <%= @student.name %> but the charge was declined. They still have time to re-enter their credit card info before the session is suspended, though.
|
||||
<% end %>
|
||||
|
||||
Best Regards,
|
||||
Team JamKazam
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
<% provide(:title, 'Welcome to JamKazam!') %>
|
||||
|
||||
|
||||
<% if !@user.anonymous? %>
|
||||
<p>Hello <%= EmailBatchProgression::VAR_FIRST_NAME %> --
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
|
||||
<p> We're delighted you have decided to join the JamKazam community of musicians, and we hope
|
||||
|
||||
you will enjoy using JamKazam and JamTracks to play more music. Following are some
|
||||
|
||||
resources and some things you can do to get the most out of JamKazam.
|
||||
</p>
|
||||
|
||||
|
||||
<p><b style="color: white;">Playing With JamTracks</b><br/>
|
||||
|
||||
JamTracks are the best way to play along with your favorite songs. Far better and different than
|
||||
|
||||
traditional backing tracks, our JamTracks are complete multi-track professional recordings, with
|
||||
|
||||
fully isolated tracks for each part of the music. And our free app and Internet service are packed
|
||||
|
||||
with features that give you unmatched creative freedom to learn, practice, record, play with
|
||||
|
||||
others, and share your performances. Here are some great JamTracks resources:
|
||||
</p>
|
||||
<ul>
|
||||
<li><a style="color:#fc0" href="https://www.youtube.com/watch?v=07zJC7C2ICA">JamTracks Overview Video</a> - See all the great things you can do with JamTracks.</li>
|
||||
<li><a style="color:#fc0" href="https://jamkazam.desk.com/customer/en/portal/articles/2124663-playing-with-jamtracks">JamTracks User Guide</a> - A set of articles that explain how to use all the JamTracks
|
||||
|
||||
features.</li>
|
||||
<li><a style="color:#fc0" href="https://www.jamkazam.com/client#/jamtrack">Get a JamTrack Free</a> - A web page you can visit to search our catalog of JamTracks.
|
||||
|
||||
When you find a song you like, click the Get It Free button, and your first one is free! If
|
||||
|
||||
you already redeemed a free JamTrack or purchased JamTracks, you can also access
|
||||
|
||||
them on this page from your web browser.</li>
|
||||
<li><a style="color:#fc0" href="https://www.jamkazam.com/downloads">JamKazam Application</a> - A web page where you can download our free Mac or Windows
|
||||
|
||||
app. The app lets you do a lot more with JamTracks than you can do in a browser.</li>
|
||||
</ul>
|
||||
|
||||
<p><b style="color: white;">Play Live With Others from Different Locations on JamKazam</b><br/>
|
||||
JamKazam’s free app lets musicians play together live and in sync from different locations over
|
||||
|
||||
the Internet. Kind of like Skype on super audio steroids, with ultra low latency and terrific audio
|
||||
|
||||
quality. You can set up online sessions that are public or private, for you alone or for others to
|
||||
|
||||
join. You can find and join others’ sessions, use backing tracks and loops in sessions, make
|
||||
|
||||
audio and video recordings of session performances, and more. <a style="color:#fc0" href="https://jamkazam.desk.com/customer/en/portal/topics/673198-tutorials-on-major-features/articles">Click here for a set of tutorial
|
||||
|
||||
videos that show how to use these features</a>.
|
||||
</p>
|
||||
|
||||
<p><b style="color: white;">Teach or Take Online Music Lessons</b><br/>
|
||||
If you teach music lessons and have tried to give lessons using Skype, you’ll know how
|
||||
|
||||
unsatisfactory that experience is. Audio quality is poor, and latency prohibits teacher and
|
||||
|
||||
student playing together at all. JamKazam is a terrific service for teaching and taking online
|
||||
|
||||
music lessons. If you want to use JamKazam for lessons, we’ll be happy to support both you and
|
||||
|
||||
your students in getting set up and ready to go.
|
||||
</p>
|
||||
|
||||
<p><b style="color: white;">Complete Your Profile</b><br/>
|
||||
Every member of our community has a profile. It’s a great way to share a little bit about who
|
||||
|
||||
you are as a musician, as well as your musical interests. For example, what instruments do you
|
||||
|
||||
play? What musical genres do you like best? Are you interested in getting into a virtual/online
|
||||
|
||||
or a real-world band? And so on. Filling out your profile will help you connect with others with
|
||||
|
||||
common interests. To do this, go to <a style="color:#fc0" href="https://www.jamkazam.com/client">www.jamkazam.com</a> or launch the JamKazam app. Then
|
||||
|
||||
click on the Profile tile, and click the Edit Profile button.
|
||||
</p>
|
||||
|
||||
<p><b style="color: white;">Invite Your Friends</b><br/>
|
||||
Have friends who are musicians? Invite them to join you to play together on JamKazam. To do
|
||||
|
||||
this, go to <a style="color:#fc0" href="https://www.jamkazam.com/client">www.jamkazam.com</a> or launch the JamKazam app. Then move your mouse over the
|
||||
|
||||
user icon in the top right corner of the screen. A menu will be displayed. Click Invite Friends in
|
||||
|
||||
this menu, and you can then use the options to invite your friends using their email addresses,
|
||||
|
||||
or via Facebook, or using your Google contacts.
|
||||
<p>
|
||||
|
||||
<p><b style="color: white;">Get Help</b><br/>
|
||||
|
||||
If you run into trouble and need help, please reach out to us. We will be glad to do everything
|
||||
|
||||
we can to answer your questions and get you up and running. You can visit our <a style="color:#fc0" href="https://jamkazam.desk.com/">Support Portal</a>
|
||||
|
||||
to find knowledge base articles and post questions that have not already been answered. You
|
||||
|
||||
can email us at <a style="color:#fc0" href="mailto:support@jamkazam.com">support@jamkazam.com</a>. And if you just want to chat, share tips and war
|
||||
|
||||
stories, and hang out with fellow JamKazamers, you can visit our <a style="color:#fc0" href="http://forums.jamkazam.com/">Community Forum</a>.
|
||||
<p>
|
||||
|
||||
<p>
|
||||
<br/>
|
||||
<br/>
|
||||
Again, welcome to JamKazam, and we hope you have a great time here!
|
||||
</p>
|
||||
|
||||
<p>Best Regards,<br/>
|
||||
Team JamKazam</p>
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
<% if !@user.anonymous? %>Hello <%= EmailBatchProgression::VAR_FIRST_NAME %> --<% end %>
|
||||
|
||||
We're delighted that you have decided to try the JamKazam service, and we hope that you will enjoy using JamKazam to play music with others. Following are some resources that can help you get oriented and get the most out of JamKazam.
|
||||
|
||||
|
||||
Getting Started
|
||||
---------------
|
||||
|
||||
There are basically three kinds of setups you can use to play on JamKazam.
|
||||
|
||||
* Built-In Audio on Your Computer - You can use a Windows or Mac computer, and just use the built-in mic and headphone jack to handle your audio. This is cheap and easy, but your audio quality will suffer, and it will also process audio very slowly, creating problems with latency, or lag, in your sessions. Still, you can at least start experimenting with JamKazam in this way.
|
||||
|
||||
* Computer with External Audio Interface - - You can use a Windows or Mac computer with an external audio interface that you already own and use for recording, if you happen to have one already. If you are going to do this, or use the built-in mic/headphones on your computer, please refer to our Minimum System Requirements at https://jamkazam.desk.com/customer/portal/articles/1288274-minimum-system-requirements to make sure your computer will work. These requirements were on the download page for the app, but you may have sped by them. Also, we'd recommend watching our Getting Started Video at https://www.youtube.com/watch?v=DBo--aj_P1w to learn more about your options here.
|
||||
|
||||
* The JamBlaster - JamKazam has designed a new product from the ground up to be the best way to play music online in real time. It's called the JamBlaster. It processes audio faster than any of the thousands of combinations of computers and interfaces in use on JamKazam today, which means you can play with musicians who are farther away from you, and closer sessions will feel/sound tighter. The JamBlaster is both a computer and an audio interface, so it also eliminates the system requirements worries, and it "just works" so you don't have to be an audio and computer genius to get it working. This is a great product - available only through a Kickstarter program running during a 30-day window during parts of February and March 2015. You can watch the JamBlaster Video at https://www.youtube.com/watch?v=gAJAIHMyois to learn more about this amazing new product.
|
||||
|
||||
|
||||
JamKazam Features
|
||||
-----------------
|
||||
|
||||
JamKazam offers a very robust and exciting set of features for playing online and sharing your performances with others. Here are some videos you can watch to easily get up to speed on some of the things you can do with JamKazam:
|
||||
|
||||
* Creating a Session - https://www.youtube.com/watch?v=EZZuGcDUoWk
|
||||
|
||||
* Finding a Session - https://www.youtube.com/watch?v=xWponSJo-GU
|
||||
|
||||
* Playing in a Session - https://www.youtube.com/watch?v=zJ68hA8-fLA
|
||||
|
||||
* Connecting with Other Musicians - https://www.youtube.com/watch?v=4KWklSZZxRc
|
||||
|
||||
* Working with Recordings - https://www.youtube.com/watch?v=Gn-dOqnNLoY
|
||||
|
||||
|
||||
Getting Help
|
||||
------------
|
||||
|
||||
If you run into trouble and need help, please reach out to us. We will be glad to do everything we can to answer your questions and get you up and running. You can visit our Support Portal at https://jamkazam.desk.com/ to find knowledge base articles and post questions that have not already been answered. You can email us at support@jamkazam.com. And if you just want to chat, share tips and war stories, and hang out with fellow JamKazamers, you can visit our Community Forum at http://forums.jamkazam.com/.
|
||||
|
||||
Again, welcome to JamKazam, and we look forward to seeing – and hearing – you online soon!
|
||||
|
||||
Best Regards,
|
||||
Team JamKazam
|
||||
|
||||
|
|
@ -5,13 +5,14 @@
|
|||
<title>JamKazam</title>
|
||||
|
||||
<style>
|
||||
p {
|
||||
margin-bottom:0px;
|
||||
line-height:140%;
|
||||
}
|
||||
a {
|
||||
color: #ffcc00 !important;
|
||||
}
|
||||
p {
|
||||
margin-bottom: 0px;
|
||||
line-height: 140%;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #ffcc00 !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
|
|
@ -25,15 +26,22 @@
|
|||
<table bgcolor="#262626" width="650" align="center" cellpadding="30" cellspacing="0">
|
||||
|
||||
<tr>
|
||||
<td align="left"><h1 style="font-size:22px;font-weight:normal;margin-top:0px"><font color="#F34E1C" face="Arial, Helvetica, sans-serif"><%= yield(:title) %></font></h1>
|
||||
<td align="left"><h1 style="font-size:22px;font-weight:normal;margin-top:0px">
|
||||
<font color="#F34E1C" face="Arial, Helvetica, sans-serif"><%= yield(:title) %></font></h1>
|
||||
|
||||
<p><font size="3" color="#AAAAAA" face="Arial, Helvetica, sans-serif"><%= yield %></font></p>
|
||||
<br>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td width="58" align="left" valign="top"><p style="padding:2px;width:54px;height:54px;background-color:#ed3618;-webkit-border-radius:28px;-moz-border-radius:28px;border-radius:28px;margin-right:10px"><img src="<%= yield(:photo_url) %>" width="54" height="54" style="-webkit-border-radius:26px;-moz-border-radius:26px;border-radius:26px;"></p></td>
|
||||
<td width="58" align="left" valign="top">
|
||||
<p style="padding:2px;width:54px;height:54px;background-color:#ed3618;-webkit-border-radius:28px;-moz-border-radius:28px;border-radius:28px;margin-right:10px">
|
||||
<img src="<%= yield(:photo_url) %>" width="54" height="54" style="-webkit-border-radius:26px;-moz-border-radius:26px;border-radius:26px;">
|
||||
</p></td>
|
||||
<td><p><font size="3" color="#AAAAAA" face="Arial, Helvetica, sans-serif"><%= yield(:note) %></font></p>
|
||||
</td></tr></table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
</td>
|
||||
|
|
@ -43,24 +51,30 @@
|
|||
|
||||
|
||||
<% unless @suppress_user_has_account_footer == true %>
|
||||
<tr>
|
||||
<td>
|
||||
<table bgcolor="#21474C" cellpadding="10" cellspacing="0">
|
||||
<tr>
|
||||
<td align="left">
|
||||
<tr>
|
||||
<td>
|
||||
<table bgcolor="#21474C" cellpadding="10" cellspacing="0">
|
||||
<tr>
|
||||
<td align="left">
|
||||
|
||||
<!-- CALL OUT BOX -->
|
||||
</font></p>
|
||||
<p style="margin-top:0px"><font size="2" color="#7FACBA" face="Arial, Helvetica, sans-serif">This email was sent to you because you have an account at <a style="color: #ffcc00;" href="https://www.jamkazam.com">JamKazam</a>.
|
||||
</td></tr></table>
|
||||
<!-- CALL OUT BOX -->
|
||||
</font></p>
|
||||
<p style="margin-top:0px">
|
||||
<font size="2" color="#7FACBA" face="Arial, Helvetica, sans-serif">This email was sent to you because
|
||||
you have an account at <a style="color: #ffcc00;" href="https://www.jamkazam.com">JamKazam</a>.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</table>
|
||||
<table align="center" width="650" cellpadding="10" bgcolor="#156572" cellspacing="0">
|
||||
<tr>
|
||||
<td align="center"><font size="1" color="#ffffff" face="Arial, Helvetica, sans-serif">Copyright © <%= Time.now.year %> JamKazam, Inc. All rights reserved.</font>
|
||||
<td align="center">
|
||||
<font size="1" color="#ffffff" face="Arial, Helvetica, sans-serif">Copyright © <%= Time.now.year %> JamKazam,
|
||||
Inc. All rights reserved.</font>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,72 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<title>JamKazam</title>
|
||||
|
||||
<style>
|
||||
p {
|
||||
margin-bottom: 0px;
|
||||
line-height: 140%;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #ffcc00 !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
|
||||
<body bgcolor="#000000" style="margin-top:10px;font-family:Arial, Helvetica, sans-serif;">
|
||||
<table bgcolor="#262626" width="650" align="center" cellpadding="0" cellspacing="0">
|
||||
<tr>
|
||||
<td><img src="https://www.jamkazam.com/assets/email/header.png" width="650" height="183" alt="JamKazam"></td>
|
||||
</tr>
|
||||
</table>
|
||||
<table bgcolor="#262626" width="650" align="center" cellpadding="30" cellspacing="0">
|
||||
|
||||
<tr>
|
||||
<td align="left"><h1 style="font-size:22px;font-weight:normal;margin-top:0px">
|
||||
<font color="#F34E1C" face="Arial, Helvetica, sans-serif"><%= yield(:title) %></font></h1>
|
||||
|
||||
<font color="#AAAAAA" face="Arial, Helvetica, sans-serif">
|
||||
<%= yield %>
|
||||
</font>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
|
||||
<% unless @suppress_user_has_account_footer == true %>
|
||||
<tr>
|
||||
<td>
|
||||
<table bgcolor="#21474C" cellpadding="10" cellspacing="0">
|
||||
<tr>
|
||||
<td align="left">
|
||||
|
||||
<!-- CALL OUT BOX -->
|
||||
</font></p>
|
||||
<p style="margin-top:0px">
|
||||
<font size="2" color="#7FACBA" face="Arial, Helvetica, sans-serif">This email was sent to you because
|
||||
you have an account at <a style="color: #ffcc00;" href="https://www.jamkazam.com">JamKazam</a>.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</table>
|
||||
<table align="center" width="650" cellpadding="10" bgcolor="#156572" cellspacing="0">
|
||||
<tr>
|
||||
<td align="center">
|
||||
<font size="1" color="#ffffff" face="Arial, Helvetica, sans-serif">Copyright © <%= Time.now.year %> JamKazam,
|
||||
Inc. All rights reserved.</font>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<%= yield %>
|
||||
|
||||
<% unless @user.nil? || @suppress_user_has_account_footer == true %>
|
||||
This email was sent to you because you have an account at JamKazam / https://www.jamkazam.com. To unsubscribe: https://www.jamkazam.com/unsubscribe/<%=@user.unsubscribe_token%>.
|
||||
<% end %>
|
||||
|
||||
Copyright <%= Time.now.year %> JamKazam, Inc. All rights reserved.
|
||||
|
|
@ -54,4 +54,7 @@ module NotificationTypes
|
|||
MIXDOWN_SIGN_COMPLETE = "MIXDOWN_SIGN_COMPLETE"
|
||||
MIXDOWN_SIGN_FAILED = "MIXDOWN_SIGN_FAILED"
|
||||
|
||||
# jamclass
|
||||
LESSON_MESSAGE = "LESSON_MESSAGE"
|
||||
SCHEDULED_JAMCLASS_INVITATION = "SCHEDULED_JAMCLASS_INVITATION"
|
||||
end
|
||||
|
|
@ -82,8 +82,32 @@ module JamRuby
|
|||
return if self.ignore # doing any writes in a test environment cause annoying puts to occur
|
||||
|
||||
if @client && data && data.length > 0
|
||||
data['host'] = @host
|
||||
data['time'] = Time.now.to_i
|
||||
if data.has_key?('values') || data.has_key?(:values)
|
||||
@client.write_point(name, data)
|
||||
data['timestamp'] = Time.now.to_i
|
||||
|
||||
tags = data['tags']
|
||||
key = 'tags' if tags
|
||||
tags ||= data[:tags]
|
||||
key = :tags if key.nil?
|
||||
tags ||= {}
|
||||
key = :tags if key.nil?
|
||||
|
||||
tags['host'] = @host
|
||||
data[key] = tags
|
||||
else
|
||||
tags = {}
|
||||
values = {}
|
||||
for k,v in data
|
||||
if v.is_a?(String)
|
||||
tags[k] = v
|
||||
else
|
||||
values[k] = v
|
||||
end
|
||||
end
|
||||
data = {tags: tags, values: values}
|
||||
end
|
||||
|
||||
@client.write_point(name, data)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -524,21 +524,41 @@ module JamRuby
|
|||
)
|
||||
end
|
||||
|
||||
def scheduled_session_invitation(receiver_id, session_id, photo_url, msg, session_name, session_date, notification_id, created_at)
|
||||
scheduled_session_invitation = Jampb::ScheduledSessionInvitation.new(
|
||||
def scheduled_jamclass_invitation(receiver_id, session_id, photo_url, msg, session_name, session_date, notification_id, created_at, lesson_session_id)
|
||||
scheduled_jamclas_invitation = Jampb::ScheduledJamclassInvitation.new(
|
||||
:session_id => session_id,
|
||||
:photo_url => photo_url,
|
||||
:msg => msg,
|
||||
:session_name => session_name,
|
||||
:session_date => session_date,
|
||||
:notification_id => notification_id,
|
||||
:created_at => created_at
|
||||
:created_at => created_at,
|
||||
lesson_session_id: lesson_session_id
|
||||
)
|
||||
|
||||
Jampb::ClientMessage.new(
|
||||
:type => ClientMessage::Type::SCHEDULED_SESSION_INVITATION,
|
||||
:type => ClientMessage::Type::SCHEDULED_JAMCLASS_INVITATION,
|
||||
:route_to => USER_TARGET_PREFIX + receiver_id,
|
||||
:scheduled_session_invitation => scheduled_session_invitation
|
||||
:scheduled_jamclass_invitation => scheduled_jamclas_invitation
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
def scheduled_session_invitation(receiver_id, session_id, photo_url, msg, session_name, session_date, notification_id, created_at)
|
||||
scheduled_session_invitation = Jampb::ScheduledSessionInvitation.new(
|
||||
:session_id => session_id,
|
||||
:photo_url => photo_url,
|
||||
:msg => msg,
|
||||
:session_name => session_name,
|
||||
:session_date => session_date,
|
||||
:notification_id => notification_id,
|
||||
:created_at => created_at
|
||||
)
|
||||
|
||||
Jampb::ClientMessage.new(
|
||||
:type => ClientMessage::Type::SCHEDULED_SESSION_INVITATION,
|
||||
:route_to => USER_TARGET_PREFIX + receiver_id,
|
||||
:scheduled_session_invitation => scheduled_session_invitation
|
||||
)
|
||||
end
|
||||
|
||||
|
|
@ -949,6 +969,29 @@ module JamRuby
|
|||
)
|
||||
end
|
||||
|
||||
# creates the general purpose text message
|
||||
def lesson_message(receiver_id, sender_photo_url, sender_name, sender_id, msg, notification_id, music_session_id, created_at, student_directed, purpose, lesson_session_id)
|
||||
lesson_message = Jampb::LessonMessage.new(
|
||||
:photo_url => sender_photo_url,
|
||||
:sender_name => sender_name,
|
||||
:sender_id => sender_id,
|
||||
:receiver_id => receiver_id,
|
||||
:msg => msg,
|
||||
:notification_id => notification_id,
|
||||
:music_session_id => music_session_id,
|
||||
:created_at => created_at,
|
||||
:student_directed => student_directed,
|
||||
:purpose => purpose,
|
||||
:lesson_session_id => lesson_session_id
|
||||
)
|
||||
|
||||
Jampb::ClientMessage.new(
|
||||
:type => ClientMessage::Type::LESSON_MESSAGE,
|
||||
:route_to => USER_TARGET_PREFIX + receiver_id,
|
||||
:lesson_message => lesson_message
|
||||
)
|
||||
end
|
||||
|
||||
# creates the chat message
|
||||
def chat_message(session_id, sender_name, sender_id, msg, msg_id, created_at, channel)
|
||||
chat_message = Jampb::ChatMessage.new(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
module JamRuby
|
||||
class AffiliateDistribution < ActiveRecord::Base
|
||||
|
||||
|
||||
belongs_to :sale_line_item, class_name: 'JamRuby::SaleLineItem'
|
||||
belongs_to :affiliate_referral, class_name: 'JamRuby::AffiliatePartner', foreign_key: :affiliate_referral_id
|
||||
|
||||
validates :affiliate_referral, presence:true
|
||||
validates :affiliate_referral_fee_in_cents, numericality: {only_integer: false}
|
||||
|
||||
def self.create(affiliate_referral, fee_in_cents, sale_line_item)
|
||||
distribution = AffiliateDistribution.new
|
||||
distribution.affiliate_referral = affiliate_referral
|
||||
distribution.affiliate_referral_fee_in_cents = fee_in_cents
|
||||
distribution.sale_line_item = sale_line_item
|
||||
distribution
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -9,6 +9,7 @@ class JamRuby::AffiliatePartner < ActiveRecord::Base
|
|||
has_many :months, :class_name => 'JamRuby::AffiliateMonthlyPayment', foreign_key: :affiliate_partner_id, inverse_of: :affiliate_partner
|
||||
has_many :traffic_totals, :class_name => 'JamRuby::AffiliateTrafficTotal', foreign_key: :affiliate_partner_id, inverse_of: :affiliate_partner
|
||||
has_many :visits, :class_name => 'JamRuby::AffiliateReferralVisit', foreign_key: :affiliate_partner_id, inverse_of: :affiliate_partner
|
||||
has_many :affiliate_distributions, :class_name => "JamRuby::AffiliateDistribution", foreign_key: :affiliate_referral_id
|
||||
attr_accessible :partner_name, :partner_code, :partner_user_id, :entity_type, :rate, as: :admin
|
||||
|
||||
ENTITY_TYPES = %w{ Individual Sole\ Proprietor Limited\ Liability\ Company\ (LLC) Partnership Trust/Estate S\ Corporation C\ Corporation Other }
|
||||
|
|
@ -118,17 +119,19 @@ class JamRuby::AffiliatePartner < ActiveRecord::Base
|
|||
sale_time - user.created_at < 2.years
|
||||
end
|
||||
|
||||
def should_attribute_sale?(shopping_cart)
|
||||
def should_attribute_sale?(shopping_cart, user_to_check, instance)
|
||||
|
||||
if created_within_affiliate_window(shopping_cart.user, Time.now)
|
||||
product_info = shopping_cart.product_info
|
||||
if created_within_affiliate_window(user_to_check, Time.now)
|
||||
product_info = shopping_cart.product_info(instance)
|
||||
# subtract the total quantity from the freebie quantity, to see how much we should attribute to them
|
||||
real_quantity = product_info[:quantity].to_i - product_info[:marked_for_redeem].to_i
|
||||
{fee_in_cents: (product_info[:price] * 100 * real_quantity * rate.to_f).round}
|
||||
|
||||
applicable_rate = shopping_cart.is_lesson? ? lesson_rate : rate
|
||||
|
||||
{fee_in_cents: (product_info[:price] * 100 * real_quantity * applicable_rate.to_f).round}
|
||||
else
|
||||
false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def cumulative_earnings_in_dollars
|
||||
|
|
@ -233,23 +236,23 @@ class JamRuby::AffiliatePartner < ActiveRecord::Base
|
|||
|
||||
def self.sale_items_subquery(start_date, end_date, table_name)
|
||||
%{
|
||||
FROM sale_line_items
|
||||
FROM affiliate_distributions inner join sale_line_items ON affiliate_distributions.sale_line_item_id = sale_line_items.id
|
||||
WHERE
|
||||
(DATE(sale_line_items.created_at) >= DATE('#{start_date}') AND DATE(sale_line_items.created_at) <= DATE('#{end_date}'))
|
||||
(DATE(affiliate_distributions.created_at) >= DATE('#{start_date}') AND DATE(affiliate_distributions.created_at) <= DATE('#{end_date}'))
|
||||
AND
|
||||
sale_line_items.affiliate_referral_id = #{table_name}.affiliate_partner_id
|
||||
affiliate_distributions.affiliate_referral_id = #{table_name}.affiliate_partner_id
|
||||
}
|
||||
end
|
||||
|
||||
def self.sale_items_refunded_subquery(start_date, end_date, table_name)
|
||||
%{
|
||||
FROM sale_line_items
|
||||
FROM affiliate_distributions inner join sale_line_items ON affiliate_distributions.sale_line_item_id = sale_line_items.id
|
||||
WHERE
|
||||
(DATE(sale_line_items.affiliate_refunded_at) >= DATE('#{start_date}') AND DATE(sale_line_items.affiliate_refunded_at) <= DATE('#{end_date}'))
|
||||
(DATE(affiliate_distributions.affiliate_refunded_at) >= DATE('#{start_date}') AND DATE(affiliate_distributions.affiliate_refunded_at) <= DATE('#{end_date}'))
|
||||
AND
|
||||
sale_line_items.affiliate_referral_id = #{table_name}.affiliate_partner_id
|
||||
affiliate_distributions.affiliate_referral_id = #{table_name}.affiliate_partner_id
|
||||
AND
|
||||
sale_line_items.affiliate_refunded = TRUE
|
||||
affiliate_distributions.affiliate_refunded = TRUE
|
||||
}
|
||||
end
|
||||
# total up quarters by looking in sale_line_items for items that are marked as having a affiliate_referral_id
|
||||
|
|
@ -269,22 +272,22 @@ class JamRuby::AffiliatePartner < ActiveRecord::Base
|
|||
last_updated = NOW(),
|
||||
jamtracks_sold =
|
||||
COALESCE(
|
||||
(SELECT COUNT(CASE WHEN sale_line_items.product_type = 'JamTrack' AND sale_line_items.affiliate_referral_fee_in_cents > 0 THEN 1 ELSE NULL END)
|
||||
(SELECT COUNT(CASE WHEN sale_line_items.product_type = 'JamTrack' AND affiliate_distributions.affiliate_referral_fee_in_cents > 0 THEN 1 ELSE NULL END)
|
||||
#{sale_items_subquery(start_date, end_date, 'affiliate_monthly_payments')}
|
||||
), 0)
|
||||
+
|
||||
COALESCE(
|
||||
(SELECT -COUNT(CASE WHEN sale_line_items.product_type = 'JamTrack' AND sale_line_items.affiliate_referral_fee_in_cents > 0 THEN 1 ELSE NULL END)
|
||||
(SELECT -COUNT(CASE WHEN sale_line_items.product_type = 'JamTrack' AND affiliate_distributions.affiliate_referral_fee_in_cents > 0 THEN 1 ELSE NULL END)
|
||||
#{sale_items_refunded_subquery(start_date, end_date, 'affiliate_monthly_payments')}
|
||||
), 0),
|
||||
due_amount_in_cents =
|
||||
COALESCE(
|
||||
(SELECT SUM(affiliate_referral_fee_in_cents)
|
||||
(SELECT SUM(affiliate_distributions.affiliate_referral_fee_in_cents)
|
||||
#{sale_items_subquery(start_date, end_date, 'affiliate_monthly_payments')}
|
||||
), 0)
|
||||
+
|
||||
COALESCE(
|
||||
(SELECT -SUM(affiliate_referral_fee_in_cents)
|
||||
(SELECT -SUM(affiliate_distributions.affiliate_referral_fee_in_cents)
|
||||
#{sale_items_refunded_subquery(start_date, end_date, 'affiliate_monthly_payments')}
|
||||
), 0)
|
||||
|
||||
|
|
@ -322,22 +325,22 @@ class JamRuby::AffiliatePartner < ActiveRecord::Base
|
|||
last_updated = NOW(),
|
||||
jamtracks_sold =
|
||||
COALESCE(
|
||||
(SELECT COUNT(CASE WHEN sale_line_items.product_type = 'JamTrack' AND sale_line_items.affiliate_referral_fee_in_cents > 0 THEN 1 ELSE NULL END)
|
||||
(SELECT COUNT(CASE WHEN sale_line_items.product_type = 'JamTrack' AND affiliate_distributions.affiliate_referral_fee_in_cents > 0 THEN 1 ELSE NULL END)
|
||||
#{sale_items_subquery(start_date, end_date, 'affiliate_quarterly_payments')}
|
||||
), 0)
|
||||
+
|
||||
COALESCE(
|
||||
(SELECT -COUNT(CASE WHEN sale_line_items.product_type = 'JamTrack' AND sale_line_items.affiliate_referral_fee_in_cents > 0 THEN 1 ELSE NULL END)
|
||||
(SELECT -COUNT(CASE WHEN sale_line_items.product_type = 'JamTrack' AND affiliate_distributions.affiliate_referral_fee_in_cents > 0 THEN 1 ELSE NULL END)
|
||||
#{sale_items_refunded_subquery(start_date, end_date, 'affiliate_quarterly_payments')}
|
||||
), 0),
|
||||
due_amount_in_cents =
|
||||
COALESCE(
|
||||
(SELECT SUM(affiliate_referral_fee_in_cents)
|
||||
(SELECT SUM(affiliate_distributions.affiliate_referral_fee_in_cents)
|
||||
#{sale_items_subquery(start_date, end_date, 'affiliate_quarterly_payments')}
|
||||
), 0)
|
||||
+
|
||||
COALESCE(
|
||||
(SELECT -SUM(affiliate_referral_fee_in_cents)
|
||||
(SELECT -SUM(affiliate_distributions.affiliate_referral_fee_in_cents)
|
||||
#{sale_items_refunded_subquery(start_date, end_date, 'affiliate_quarterly_payments')}
|
||||
), 0)
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
module JamRuby
|
||||
class AffiliatePaymentCharge < Charge
|
||||
|
||||
has_one :teacher_payment, class_name: "JamRuby::TeacherPayment", foreign_key: :affiliate_charge_id
|
||||
|
||||
def distribution
|
||||
@distribution ||= teacher_payment.teacher_distribution
|
||||
end
|
||||
|
||||
def max_retries
|
||||
9999999
|
||||
end
|
||||
|
||||
def teacher
|
||||
@teacher ||= teacher_payment.teacher
|
||||
end
|
||||
|
||||
def charged_user
|
||||
teacher
|
||||
end
|
||||
|
||||
def do_charge
|
||||
|
||||
# source will let you supply a token. But... how to get a token in this case?
|
||||
|
||||
stripe_charge = Stripe::Charge.create(
|
||||
:amount => amount_in_cents,
|
||||
:currency => "usd",
|
||||
:customer => APP_CONFIG.stripe[:source_customer],
|
||||
:description => construct_description,
|
||||
:destination => teacher.teacher.stripe_account_id,
|
||||
:application_fee => fee_in_cents,
|
||||
)
|
||||
|
||||
stripe_charge
|
||||
end
|
||||
|
||||
def do_send_notices
|
||||
UserMailer.teacher_distribution_done(teacher_payment)
|
||||
end
|
||||
|
||||
def do_send_unable_charge
|
||||
UserMailer.teacher_distribution_fail(teacher_payment)
|
||||
end
|
||||
|
||||
def construct_description
|
||||
teacher_payment.teacher_distribution.description
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
module JamRuby
|
||||
class Charge < ActiveRecord::Base
|
||||
|
||||
validates :sent_billing_notices, inclusion: {in: [true, false]}
|
||||
|
||||
def max_retries
|
||||
raise "not implemented"
|
||||
end
|
||||
def do_charge(force)
|
||||
raise "not implemented"
|
||||
end
|
||||
def do_send_notices
|
||||
raise "not implemented"
|
||||
end
|
||||
def do_send_unable_charge
|
||||
raise "not implemented"
|
||||
end
|
||||
def charge_retry_hours
|
||||
24
|
||||
end
|
||||
def charged_user
|
||||
raise "not implemented"
|
||||
end
|
||||
|
||||
def charge(force = false)
|
||||
|
||||
stripe_charge = nil
|
||||
|
||||
if !self.billed
|
||||
|
||||
# check if we can bill at the moment
|
||||
if !force && last_billing_attempt_at && (charge_retry_hours.hours.ago < last_billing_attempt_at)
|
||||
return false
|
||||
end
|
||||
|
||||
if !force && !billing_should_retry
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
# bill the user right now. if it fails, move on; will be tried again
|
||||
self.billing_attempts = self.billing_attempts + 1
|
||||
self.billing_should_retry = self.billing_attempts < max_retries
|
||||
self.last_billing_attempt_at = Time.now
|
||||
self.save(validate: false)
|
||||
|
||||
begin
|
||||
|
||||
stripe_charge = do_charge(force)
|
||||
self.stripe_charge_id = stripe_charge.id
|
||||
self.billed = true
|
||||
self.billed_at = Time.now
|
||||
self.save(validate: false)
|
||||
rescue Stripe::StripeError => e
|
||||
|
||||
stripe_handler(e)
|
||||
|
||||
subject = "Unable to charge user #{charged_user.email} for lesson #{self.id} (stripe)"
|
||||
body = "user=#{charged_user.email}\n\nbilling_error_reason=#{billing_error_reason}\n\nbilling_error_detail = #{billing_error_detail}"
|
||||
AdminMailer.alerts({subject: subject, body: body})
|
||||
do_send_unable_charge
|
||||
|
||||
return false
|
||||
rescue Exception => e
|
||||
subject = "Unable to charge user #{charged_user.email} for lesson #{self.id} (unhandled)"
|
||||
body = "user=#{charged_user.email}\n\nbilling_error_reason=#{billing_error_reason}\n\nbilling_error_detail = #{billing_error_detail}"
|
||||
AdminMailer.alerts({subject: subject, body: body})
|
||||
unhandled_handler(e)
|
||||
return false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if !self.sent_billing_notices
|
||||
# If the charge is successful, then we post the charge to the student’s payment history,
|
||||
# and associate the charge with the lesson, so that everyone knows the student has paid, and we send an email
|
||||
|
||||
do_send_notices
|
||||
|
||||
self.sent_billing_notices = true
|
||||
self.sent_billing_notices_at = Time.now
|
||||
self.post_processed = true
|
||||
self.post_processed_at = Time.now
|
||||
self.save(validate: false)
|
||||
end
|
||||
|
||||
return stripe_charge
|
||||
end
|
||||
|
||||
def unhandled_handler(e, reason = 'unhandled_exception')
|
||||
self.billing_error_reason = reason
|
||||
if e.cause
|
||||
self.billing_error_detail = e.cause.to_s + "\n" + e.cause.backtrace.join("\n\t") if e.cause.backtrace
|
||||
self.billing_error_detail << "\n\n"
|
||||
self.billing_error_detail << e.to_s + "\n" + e.backtrace.join("\n\t") if e.backtrace
|
||||
else
|
||||
self.billing_error_detail = e.to_s + "\n" + e.backtrace.join("\n\t") if e.backtrace
|
||||
end
|
||||
self.save(validate: false)
|
||||
end
|
||||
|
||||
def is_card_declined?
|
||||
billed == false && billing_error_reason == 'card_declined'
|
||||
end
|
||||
|
||||
def is_card_expired?
|
||||
billed == false && billing_error_reason == 'card_expired'
|
||||
end
|
||||
|
||||
def last_billed_at_date
|
||||
last_billing_attempt_at.strftime("%B %d, %Y") if last_billing_attempt_at
|
||||
end
|
||||
def stripe_handler(e)
|
||||
|
||||
msg = e.to_s
|
||||
|
||||
if msg.include?('declined')
|
||||
self.billing_error_reason = 'card_declined'
|
||||
self.billing_error_detail = msg
|
||||
elsif msg.include?('expired')
|
||||
self.billing_error_reason = 'card_expired'
|
||||
self.billing_error_detail = msg
|
||||
elsif msg.include?('processing')
|
||||
self.billing_error_reason = 'processing_error'
|
||||
self.billing_error_detail = msg
|
||||
else
|
||||
self.billing_error_reason = 'stripe'
|
||||
self.billing_error_detail = msg
|
||||
end
|
||||
|
||||
self.save(validate: false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -3,18 +3,42 @@ module JamRuby
|
|||
include HtmlSanitize
|
||||
html_sanitize strict: [:message]
|
||||
|
||||
CHANNEL_LESSON = 'lesson'
|
||||
self.table_name = 'chat_messages'
|
||||
self.primary_key = 'id'
|
||||
|
||||
default_scope order('created_at DESC')
|
||||
|
||||
attr_accessor :ignore_message_checks
|
||||
|
||||
attr_accessible :user_id, :message, :music_session_id
|
||||
|
||||
belongs_to :user
|
||||
belongs_to :music_session
|
||||
belongs_to :target_user, class_name: "JamRuby::User"
|
||||
belongs_to :lesson_booking, class_name: "JamRuby::LessonBooking"
|
||||
|
||||
validates :user, presence: true
|
||||
validates :message, length: {minimum: 1, maximum: 255}, no_profanity: 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)
|
||||
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
|
||||
|
||||
if lesson_booking
|
||||
chat_msg.ignore_message_checks = true
|
||||
end
|
||||
|
||||
if chat_msg.save
|
||||
ChatMessage.send_chat_msg music_session, chat_msg, user, client_id, channel
|
||||
end
|
||||
chat_msg
|
||||
end
|
||||
|
||||
class << self
|
||||
|
||||
|
|
@ -36,7 +60,7 @@ module JamRuby
|
|||
query = ChatMessage.where('music_session_id = ?', music_session_id)
|
||||
end
|
||||
|
||||
query = query.offset(start).limit(limit).order('created_at DESC')
|
||||
query = query.offset(start).limit(limit).order('created_at DESC').includes([:user])
|
||||
|
||||
if query.length == 0
|
||||
[query, nil]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
module JamRuby
|
||||
class Invitation < ActiveRecord::Base
|
||||
|
||||
INVITATION_NOT_TEACHER_VALIDATION_ERROR = "Lessons can only sent invitations to teachers"
|
||||
FRIENDSHIP_REQUIRED_VALIDATION_ERROR = "You can only invite friends"
|
||||
MEMBERSHIP_REQUIRED_OF_MUSIC_SESSION = "You must be a member of the music session to send invitations on behalf of it"
|
||||
JOIN_REQUEST_IS_NOT_FOR_RECEIVER_AND_MUSIC_SESSION = "You can only associate a join request with an invitation if that join request comes from the invited user and if it's for the same music session"
|
||||
|
|
@ -15,7 +16,7 @@ module JamRuby
|
|||
validates :receiver, :presence => true
|
||||
validates :music_session, :presence => true
|
||||
|
||||
validate :require_sender_in_music_session, :require_are_friends_or_requested_to_join
|
||||
validate :require_sender_in_music_session, :require_are_friends_or_requested_to_join_or_teacher
|
||||
|
||||
private
|
||||
|
||||
|
|
@ -25,15 +26,22 @@ module JamRuby
|
|||
end
|
||||
end
|
||||
|
||||
def require_are_friends_or_requested_to_join
|
||||
def require_are_friends_or_requested_to_join_or_teacher
|
||||
if !join_request.nil? && (join_request.user != receiver || join_request.music_session != music_session)
|
||||
errors.add(:join_request, JOIN_REQUEST_IS_NOT_FOR_RECEIVER_AND_MUSIC_SESSION )
|
||||
elsif join_request.nil?
|
||||
# we only check for friendship requirement if this was not in response to a join_request
|
||||
unless receiver.friends.exists? sender
|
||||
errors.add(:receiver, FRIENDSHIP_REQUIRED_VALIDATION_ERROR)
|
||||
if !receiver.friends.exists?(sender) && (music_session.is_lesson? && receiver != music_session.lesson_session.teacher)
|
||||
if !receiver.friends.exists?(sender)
|
||||
errors.add(:receiver, FRIENDSHIP_REQUIRED_VALIDATION_ERROR)
|
||||
elsif (music_session.is_lesson? && receiver != music_session.lesson_session.teacher)
|
||||
errors.add(:receiver, INVITATION_NOT_TEACHER_VALIDATION_ERROR)
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -338,6 +338,7 @@ module JamRuby
|
|||
query = query.select("original_artist, array_agg(jam_tracks.id) AS id, MIN(name) AS name, MIN(description) AS description, MIN(recording_type) AS recording_type, MIN(original_artist) AS original_artist, MIN(songwriter) AS songwriter, MIN(publisher) AS publisher, MIN(sales_region) AS sales_region, MIN(price) AS price, MIN(version) AS version")
|
||||
query = query.group("original_artist")
|
||||
query = query.order('jam_tracks.original_artist')
|
||||
query = query.includes([{ jam_track_tracks: :instrument }, { genres_jam_tracks: :genre }])
|
||||
else
|
||||
query = query.group("jam_tracks.id")
|
||||
if options[:sort_by] == 'jamtrack'
|
||||
|
|
|
|||
|
|
@ -0,0 +1,826 @@
|
|||
# represenst the type of lesson package
|
||||
module JamRuby
|
||||
class LessonBooking < ActiveRecord::Base
|
||||
|
||||
include HtmlSanitize
|
||||
html_sanitize strict: [:description, :cancel_message]
|
||||
|
||||
include ActiveModel::Dirty
|
||||
|
||||
@@log = Logging.logger[LessonBooking]
|
||||
|
||||
attr_accessor :accepting, :countering, :countered_slot, :countered_lesson
|
||||
|
||||
STATUS_REQUESTED = 'requested'
|
||||
STATUS_CANCELED = 'canceled'
|
||||
STATUS_APPROVED = 'approved'
|
||||
STATUS_SUSPENDED = 'suspended'
|
||||
STATUS_COUNTERED = 'countered'
|
||||
|
||||
STATUS_TYPES = [STATUS_REQUESTED, STATUS_CANCELED, STATUS_APPROVED, STATUS_SUSPENDED, STATUS_COUNTERED]
|
||||
|
||||
LESSON_TYPE_FREE = 'single-free'
|
||||
LESSON_TYPE_TEST_DRIVE = 'test-drive'
|
||||
LESSON_TYPE_PAID = 'paid'
|
||||
|
||||
LESSON_TYPES = [LESSON_TYPE_FREE, LESSON_TYPE_TEST_DRIVE, LESSON_TYPE_PAID]
|
||||
|
||||
PAYMENT_STYLE_ELSEWHERE = 'elsewhere'
|
||||
PAYMENT_STYLE_SINGLE = 'single'
|
||||
PAYMENT_STYLE_WEEKLY = 'weekly'
|
||||
PAYMENT_STYLE_MONTHLY = 'monthly'
|
||||
|
||||
|
||||
PAYMENT_STYLES = [PAYMENT_STYLE_ELSEWHERE, PAYMENT_STYLE_SINGLE, PAYMENT_STYLE_WEEKLY, PAYMENT_STYLE_MONTHLY]
|
||||
|
||||
belongs_to :user, class_name: "JamRuby::User"
|
||||
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"
|
||||
|
||||
validates :user, presence: true
|
||||
validates :teacher, presence: true
|
||||
validates :lesson_type, inclusion: {in: LESSON_TYPES}
|
||||
validates :status, presence: true, inclusion: {in: STATUS_TYPES}
|
||||
validates :recurring, inclusion: {in: [true, false]}
|
||||
validates :sent_notices, inclusion: {in: [true, false]}
|
||||
validates :card_presumed_ok, inclusion: {in: [true, false]}
|
||||
validates :active, inclusion: {in: [true, false]}
|
||||
validates :lesson_length, inclusion: {in: [30, 45, 60, 90, 120]}
|
||||
validates :payment_style, inclusion: {in: PAYMENT_STYLES}
|
||||
validates :booked_price, presence: true
|
||||
validates :description, no_profanity: true, length: {minimum: 10, maximum: 20000}
|
||||
|
||||
validate :validate_user, on: :create
|
||||
validate :validate_recurring
|
||||
validate :validate_lesson_booking_slots
|
||||
validate :validate_lesson_length
|
||||
validate :validate_payment_style
|
||||
validate :validate_accepted, :if => :accepting
|
||||
|
||||
|
||||
before_save :before_save
|
||||
before_validation :before_validation
|
||||
after_create :after_create
|
||||
around_save :around_update
|
||||
|
||||
scope :test_drive, -> { where(lesson_type: LESSON_TYPE_TEST_DRIVE) }
|
||||
scope :active, -> { where(active: true) }
|
||||
scope :approved, -> { where(status: STATUS_APPROVED) }
|
||||
scope :requested, -> { where(status: STATUS_REQUESTED) }
|
||||
scope :canceled, -> { where(status: STATUS_CANCELED) }
|
||||
scope :suspended, -> { where(status: STATUS_SUSPENDED) }
|
||||
scope :engaged, -> { where("status = '#{STATUS_APPROVED}' OR status = '#{STATUS_REQUESTED}' OR status = '#{STATUS_SUSPENDED}'") }
|
||||
|
||||
def before_validation
|
||||
if self.booked_price.nil?
|
||||
self.booked_price = compute_price
|
||||
end
|
||||
end
|
||||
|
||||
def after_create
|
||||
if card_presumed_ok && !sent_notices
|
||||
send_notices
|
||||
end
|
||||
end
|
||||
|
||||
def before_save
|
||||
automatically_default_slot
|
||||
end
|
||||
|
||||
def around_update
|
||||
|
||||
@default_slot_did_change = self.default_slot_id_changed?
|
||||
|
||||
yield
|
||||
|
||||
sync_lessons
|
||||
sync_remaining_test_drives
|
||||
|
||||
@default_slot_did_change = nil
|
||||
@accepting = nil
|
||||
@countering = nil
|
||||
end
|
||||
|
||||
# here for shopping_cart
|
||||
def product_info
|
||||
{price: booked_price, real_price: booked_price, total_price: booked_price}
|
||||
end
|
||||
# here for shopping_cart
|
||||
def price
|
||||
booked_price
|
||||
end
|
||||
|
||||
|
||||
def alt_slot
|
||||
found = nil
|
||||
lesson_booking_slots.each do |slot|
|
||||
if slot.id != default_slot.id
|
||||
found = slot
|
||||
break
|
||||
end
|
||||
end
|
||||
found
|
||||
end
|
||||
|
||||
def student
|
||||
user
|
||||
end
|
||||
|
||||
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
|
||||
LessonSession.find(session.id) if session
|
||||
else
|
||||
lesson_sessions[0]
|
||||
end
|
||||
end
|
||||
|
||||
def accept(lesson_session, slot, accepter)
|
||||
if !is_active?
|
||||
self.accepting = true
|
||||
end
|
||||
|
||||
self.active = true
|
||||
self.status = STATUS_APPROVED
|
||||
self.counter_slot = nil
|
||||
self.default_slot = slot
|
||||
self.accepter = accepter
|
||||
|
||||
success = self.save
|
||||
|
||||
if !success
|
||||
puts "unable to accept lesson booking #{errors.inspect}"
|
||||
end
|
||||
success
|
||||
end
|
||||
|
||||
def counter(lesson_session, proposer, slot)
|
||||
self.countering = true
|
||||
self.lesson_booking_slots << slot
|
||||
self.counter_slot = slot
|
||||
#self.status = STATUS_COUNTERED
|
||||
self.save
|
||||
end
|
||||
|
||||
def automatically_default_slot
|
||||
if is_requested?
|
||||
if lesson_booking_slots.length > 0
|
||||
self.default_slot = lesson_booking_slots[0]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def sync_remaining_test_drives
|
||||
if is_test_drive? || is_single_free?
|
||||
if card_presumed_ok && !user_decremented
|
||||
self.user_decremented = true
|
||||
self.save(validate: false)
|
||||
if is_single_free?
|
||||
user.remaining_free_lessons = user.remaining_free_lessons - 1
|
||||
elsif is_test_drive?
|
||||
user.remaining_test_drives = user.remaining_test_drives - 1
|
||||
end
|
||||
user.save(validate: false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def create_minimum_booking_time
|
||||
# trying to be too smart
|
||||
#(Time.now + APP_CONFIG.minimum_lesson_booking_hrs * 60*60)
|
||||
Time.now
|
||||
end
|
||||
|
||||
def sync_lessons
|
||||
|
||||
if is_canceled?
|
||||
# don't create new sessions if cancelled
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
if @default_slot_did_change
|
||||
|
||||
end
|
||||
# Here we go; let's create a lesson(s) as needed
|
||||
|
||||
# we need to make lessons into the future a bit, to give time for everyone involved
|
||||
minimum_start_time = create_minimum_booking_time
|
||||
|
||||
# get all sessions that are already scheduled for this booking ahead of the minimum time
|
||||
sessions = MusicSession.joins(:lesson_session).where("lesson_sessions.lesson_booking_id = ?", id).where("scheduled_start is not null").where("scheduled_start > ?", minimum_start_time).order(:created_at)
|
||||
|
||||
if @default_slot_did_change
|
||||
# # adjust all session times
|
||||
|
||||
offset = 0
|
||||
sessions.each_with_index do |item, i|
|
||||
item.lesson_session.slot = default_slot
|
||||
result = item.lesson_session.update_next_available_time(offset)
|
||||
if result
|
||||
offset = result
|
||||
offset += 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
needed_sessions = determine_needed_sessions(sessions)
|
||||
|
||||
# if the latest scheduled session is after the minimum start time, then bump up minimum start time
|
||||
last_session = sessions.last
|
||||
last_session.reload if last_session # because of @default_slot_did_change logic above, this can be necessary
|
||||
|
||||
if last_session && last_session.scheduled_start && last_session.scheduled_start > minimum_start_time
|
||||
minimum_start_time = last_session.scheduled_start
|
||||
end
|
||||
times = default_slot.scheduled_times(needed_sessions, minimum_start_time)
|
||||
|
||||
scheduled_lessons(times)
|
||||
end
|
||||
|
||||
# sensitive to current time
|
||||
def predicted_times_for_month(year, month)
|
||||
first_day = Date.new(year, month, 1)
|
||||
last_day = Date.new(year, month, -1)
|
||||
sessions = MusicSession.joins(:lesson_session).where("lesson_sessions.lesson_booking_id = ?", id).where("scheduled_start >= ?", first_day).where("scheduled_start <= ?", last_day).order(:created_at)
|
||||
|
||||
times = []
|
||||
|
||||
sessions.each do |session|
|
||||
times << session.scheduled_start
|
||||
end
|
||||
last_session = sessions.last
|
||||
|
||||
start_day = first_day
|
||||
if last_session
|
||||
start_day = last_session.scheduled_start.to_date + 1
|
||||
end
|
||||
|
||||
# now flesh out the rest of the month with predicted times
|
||||
|
||||
more_times = default_slot.scheduled_times(5, start_day)
|
||||
|
||||
more_times.each do |time|
|
||||
if time.to_date >= first_day && time.to_date <= last_day
|
||||
times << time
|
||||
end
|
||||
end
|
||||
times
|
||||
end
|
||||
|
||||
def determine_needed_sessions(sessions)
|
||||
needed_sessions = 0
|
||||
if is_requested?
|
||||
# in the case of a requested booking (not approved) only make one, even if it's recurring. This is for UI considerations
|
||||
if sessions.count == 0
|
||||
needed_sessions = 1
|
||||
end
|
||||
elsif is_active?
|
||||
expected_num_sessions = recurring ? 2 : 1
|
||||
needed_sessions = expected_num_sessions - sessions.count
|
||||
end
|
||||
needed_sessions
|
||||
end
|
||||
|
||||
def scheduled_lessons(times)
|
||||
times.each do |time|
|
||||
|
||||
lesson_session = LessonSession.create(self)
|
||||
|
||||
if lesson_session.errors.any?
|
||||
puts "JamClass lesson session creation errors #{lesson_session.errors.inspect}"
|
||||
@@log.error("JamClass lesson session creation errors #{lesson_session.errors.inspect}")
|
||||
raise ActiveRecord::Rollback
|
||||
end
|
||||
ms_tz = ActiveSupport::TimeZone.new(default_slot.timezone)
|
||||
ms_tz = "#{ms_tz.name},#{default_slot.timezone}"
|
||||
|
||||
rsvps = [{instrument_id: 'other', proficiency_level: 0, approve: true}]
|
||||
|
||||
music_session = MusicSession.create(student, {
|
||||
name: "#{display_type2} JamClass taught by #{teacher.name}",
|
||||
description: "This is a #{lesson_length}-minute #{display_type2} lesson with #{teacher.name}.",
|
||||
musician_access: false,
|
||||
fan_access: false,
|
||||
genres: ['other'],
|
||||
approval_required: false,
|
||||
fan_chat: false,
|
||||
legal_policy: "standard",
|
||||
language: 'eng',
|
||||
duration: lesson_length,
|
||||
recurring_mode: false,
|
||||
timezone: ms_tz,
|
||||
create_type: MusicSession::CREATE_TYPE_LESSON,
|
||||
is_unstructured_rsvp: true,
|
||||
scheduled_start: time,
|
||||
invitations: [teacher.id],
|
||||
lesson_session: lesson_session,
|
||||
rsvp_slots: rsvps
|
||||
})
|
||||
|
||||
if music_session.errors.any?
|
||||
puts "JamClass lesson scheduling errors #{music_session.errors.inspect}"
|
||||
@@log.error("JamClass lesson scheduling errors #{music_session.errors.inspect}")
|
||||
raise ActiveRecord::Rollback
|
||||
end
|
||||
|
||||
if lesson_session.is_active?
|
||||
# send out email to student to act as something they can add to their calendar
|
||||
Notification.send_student_jamclass_invitation(music_session, student)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
def is_weekly_payment?
|
||||
payment_style == PAYMENT_STYLE_WEEKLY
|
||||
end
|
||||
|
||||
def is_monthly_payment?
|
||||
payment_style == PAYMENT_STYLE_MONTHLY
|
||||
end
|
||||
|
||||
def requires_per_session_billing?
|
||||
is_normal? && !is_monthly_payment?
|
||||
end
|
||||
|
||||
def requires_teacher_distribution?(target)
|
||||
if target.is_a?(JamRuby::LessonSession)
|
||||
is_test_drive? || (is_normal? && !is_monthly_payment?)
|
||||
elsif target.is_a?(JamRuby::LessonPackagePurchase)
|
||||
is_monthly_payment?
|
||||
else
|
||||
raise "unable to determine object type of #{target}"
|
||||
end
|
||||
end
|
||||
|
||||
def is_requested?
|
||||
status == STATUS_REQUESTED
|
||||
end
|
||||
|
||||
def is_canceled?
|
||||
status == STATUS_CANCELED
|
||||
end
|
||||
|
||||
def is_approved?
|
||||
status == STATUS_APPROVED
|
||||
end
|
||||
|
||||
def is_suspended?
|
||||
status == STATUS_SUSPENDED
|
||||
end
|
||||
|
||||
def is_active?
|
||||
active
|
||||
end
|
||||
|
||||
def validate_accepted
|
||||
# accept is multipe purpose; either accept the initial request, or a counter slot
|
||||
if self.status_was != STATUS_REQUESTED && counter_slot.nil? # && self.status_was != STATUS_COUNTERED
|
||||
self.errors.add(:status, "This lesson is already #{self.status}.")
|
||||
end
|
||||
|
||||
self.accepting = false
|
||||
end
|
||||
|
||||
def send_notices
|
||||
UserMailer.student_lesson_request(self).deliver
|
||||
UserMailer.teacher_lesson_request(self).deliver
|
||||
Notification.send_lesson_message('requested', lesson_sessions[0], false) # TODO: this isn't quite an 'accept'
|
||||
self.sent_notices = true
|
||||
self.save
|
||||
end
|
||||
|
||||
def lesson_package_type
|
||||
if is_single_free?
|
||||
LessonPackageType.single_free
|
||||
elsif is_test_drive?
|
||||
LessonPackageType.test_drive
|
||||
elsif is_normal?
|
||||
LessonPackageType.single
|
||||
end
|
||||
end
|
||||
|
||||
def display_type2
|
||||
if is_single_free?
|
||||
"Free"
|
||||
elsif is_test_drive?
|
||||
"TestDrive"
|
||||
elsif is_normal?
|
||||
"Single"
|
||||
end
|
||||
end
|
||||
|
||||
def display_type
|
||||
if is_single_free?
|
||||
"Free"
|
||||
elsif is_test_drive?
|
||||
"TestDrive"
|
||||
elsif is_normal?
|
||||
if recurring
|
||||
"recurring"
|
||||
else
|
||||
"single"
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
# determine the price of this booking based on what the user wants, and the teacher's pricing
|
||||
|
||||
def compute_price
|
||||
if is_single_free?
|
||||
0
|
||||
elsif is_test_drive?
|
||||
LessonPackageType.test_drive.price
|
||||
elsif is_normal?
|
||||
teacher.teacher.booking_price(lesson_length, payment_style != PAYMENT_STYLE_MONTHLY)
|
||||
end
|
||||
end
|
||||
|
||||
def distribution_price_in_cents
|
||||
if is_single_free?
|
||||
0
|
||||
elsif is_test_drive?
|
||||
10 * 100
|
||||
elsif is_normal?
|
||||
booked_price * 100
|
||||
end
|
||||
end
|
||||
|
||||
def is_single_free?
|
||||
lesson_type == LESSON_TYPE_FREE
|
||||
end
|
||||
|
||||
def is_test_drive?
|
||||
lesson_type == LESSON_TYPE_TEST_DRIVE
|
||||
end
|
||||
|
||||
def is_normal?
|
||||
lesson_type == LESSON_TYPE_PAID
|
||||
end
|
||||
|
||||
def dayWeekDesc(slot = default_slot)
|
||||
day = case slot.day_of_week
|
||||
when 0 then "Sunday"
|
||||
when 1 then "Monday"
|
||||
when 2 then "Tuesday"
|
||||
when 3 then "Wednesday"
|
||||
when 4 then "Thursday"
|
||||
when 5 then "Friday"
|
||||
when 6 then "Saturday"
|
||||
end
|
||||
|
||||
|
||||
if slot.hour > 11
|
||||
hour = slot.hour - 12
|
||||
if hour == 0
|
||||
hour = 12
|
||||
end
|
||||
am_pm = 'pm'
|
||||
else
|
||||
hour = slot.hour
|
||||
if hour == 0
|
||||
hour = 12
|
||||
end
|
||||
am_pm = 'am'
|
||||
end
|
||||
|
||||
"#{day} at #{hour}:#{slot.minute}#{am_pm}"
|
||||
|
||||
end
|
||||
|
||||
def approved_before?
|
||||
!self.accepter_id.nil?
|
||||
end
|
||||
def cancel(canceler, other, message)
|
||||
|
||||
self.active = false
|
||||
self.status = STATUS_CANCELED
|
||||
self.cancel_message = message
|
||||
self.canceler = canceler
|
||||
success = save
|
||||
if success
|
||||
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"
|
||||
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"
|
||||
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"
|
||||
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)
|
||||
|
||||
end
|
||||
|
||||
success
|
||||
end
|
||||
|
||||
def card_approved
|
||||
self.card_presumed_ok = true
|
||||
if self.save && !sent_notices
|
||||
send_notices
|
||||
end
|
||||
end
|
||||
|
||||
def validate_user
|
||||
if card_presumed_ok && is_single_free?
|
||||
if !user.has_free_lessons?
|
||||
errors.add(:user, 'have no remaining free lessons')
|
||||
end
|
||||
|
||||
#if !user.has_stored_credit_card?
|
||||
# errors.add(:user, 'has no credit card stored')
|
||||
#end
|
||||
elsif is_test_drive?
|
||||
if user.has_requested_test_drive?(teacher) && !user.admin
|
||||
errors.add(:user, "has 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")
|
||||
end
|
||||
elsif is_normal?
|
||||
#if !user.has_stored_credit_card?
|
||||
# errors.add(:user, 'has no credit card stored')
|
||||
#end
|
||||
end
|
||||
end
|
||||
|
||||
def validate_teacher
|
||||
# shouldn't we check if the teacher already has a booking in this time slot, or at least warn the user
|
||||
end
|
||||
|
||||
def validate_recurring
|
||||
if is_single_free? || is_test_drive?
|
||||
if recurring
|
||||
errors.add(:recurring, "can not be true for this type of lesson")
|
||||
end
|
||||
end
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
def validate_lesson_booking_slots
|
||||
if lesson_booking_slots.length == 0 || lesson_booking_slots.length == 1
|
||||
errors.add(:lesson_booking_slots, "must have two times specified")
|
||||
end
|
||||
end
|
||||
|
||||
def validate_lesson_length
|
||||
if is_single_free? || is_test_drive?
|
||||
if lesson_length != 30
|
||||
errors.add(:lesson_length, "must be 30 minutes")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def validate_payment_style
|
||||
if is_normal?
|
||||
if payment_style.nil?
|
||||
errors.add(:payment_style, "can't be blank")
|
||||
end
|
||||
end
|
||||
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)
|
||||
end
|
||||
|
||||
def self.book_test_drive(user, teacher, lesson_booking_slots, description)
|
||||
self.book(user, teacher, LessonBooking::LESSON_TYPE_TEST_DRIVE, lesson_booking_slots, false, 30, PAYMENT_STYLE_ELSEWHERE, description)
|
||||
end
|
||||
|
||||
def self.book_normal(user, teacher, lesson_booking_slots, description, recurring, payment_style, lesson_length)
|
||||
self.book(user, teacher, LessonBooking::LESSON_TYPE_PAID, lesson_booking_slots, recurring, lesson_length, payment_style, description)
|
||||
end
|
||||
|
||||
def self.book(user, teacher, lesson_type, lesson_booking_slots, recurring, lesson_length, payment_style, description)
|
||||
|
||||
lesson_booking = nil
|
||||
LessonBooking.transaction do
|
||||
|
||||
lesson_booking = LessonBooking.new
|
||||
lesson_booking.user = user
|
||||
lesson_booking.card_presumed_ok = user.has_stored_credit_card?
|
||||
lesson_booking.sent_notices = false
|
||||
lesson_booking.teacher = teacher
|
||||
lesson_booking.lesson_type = lesson_type
|
||||
lesson_booking.recurring = recurring
|
||||
lesson_booking.lesson_length = lesson_length
|
||||
lesson_booking.payment_style = payment_style
|
||||
lesson_booking.description = description
|
||||
lesson_booking.status = STATUS_REQUESTED
|
||||
|
||||
# two-way association slots, for before_validation loic in slot to work
|
||||
lesson_booking.lesson_booking_slots = lesson_booking_slots
|
||||
lesson_booking_slots.each do |slot|
|
||||
slot.lesson_booking = lesson_booking
|
||||
slot.message = description
|
||||
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)
|
||||
end
|
||||
end
|
||||
lesson_booking
|
||||
end
|
||||
|
||||
def self.unprocessed(current_user)
|
||||
LessonBooking.where(user_id: current_user.id).where(card_presumed_ok: false)
|
||||
end
|
||||
|
||||
def self.requested(current_user)
|
||||
LessonBooking.where(user_id: current_user.id).where(status: STATUS_REQUESTED)
|
||||
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')
|
||||
end
|
||||
|
||||
# check for any recurring sessions where there are not at least 2 sessions into the future. If not, we need to make sure they get made
|
||||
def self.hourly_check
|
||||
schedule_upcoming_lessons
|
||||
bill_monthlies
|
||||
end
|
||||
|
||||
def self.bill_monthlies
|
||||
now = Time.now
|
||||
billable_monthlies(now).each do |lesson_booking|
|
||||
lesson_booking.bill_monthly(now)
|
||||
end
|
||||
|
||||
today = now.to_date
|
||||
seven_days_in_future = today + 7
|
||||
|
||||
|
||||
is_different_month = seven_days_in_future.month != today.month
|
||||
if is_different_month
|
||||
next_month = seven_days_in_future.to_time
|
||||
billable_monthlies(next_month).each do |lesson_booking|
|
||||
lesson_booking.bill_monthly(next_month)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.billable_monthlies(now)
|
||||
current_month_first_day = Date.new(now.year, now.month, 1)
|
||||
current_month_last_day = Date.new(now.year, now.month, -1)
|
||||
#next_month_last_day = now.month == 12 ? Date.new(now.year + 1, 1, -1) : Date.new(now.year, now.month + 1, -1)
|
||||
|
||||
LessonBooking
|
||||
.joins(:lesson_sessions => :music_session)
|
||||
.joins("LEFT JOIN lesson_package_purchases ON (lesson_package_purchases.lesson_booking_id = lesson_bookings.id AND (lesson_package_purchases.year = #{current_month_first_day.year} AND lesson_package_purchases.month = #{current_month_first_day.month}))")
|
||||
.where("lesson_package_purchases.id IS NULL OR (lesson_package_purchases.id IS NOT NULL AND lesson_package_purchases.post_processed = false)")
|
||||
.where(payment_style: PAYMENT_STYLE_MONTHLY)
|
||||
.active
|
||||
.where('music_sessions.scheduled_start >= ?', current_month_first_day)
|
||||
.where('music_sessions.scheduled_start <= ?', current_month_last_day).uniq
|
||||
|
||||
=begin
|
||||
today = now.to_date
|
||||
seven_days_in_future = today + 7
|
||||
|
||||
is_different_month = seven_days_in_future.month != today.month
|
||||
if is_different_month
|
||||
condition = "(((lesson_package_purchases.year = #{current_month_first_day.year} AND lesson_package_purchases.month = #{current_month_first_day.month}) AND ( (EXTRACT(YEAR FROM lesson_sessions.created_at)) = #{current_month_first_day.year} AND (EXTRACT(MONTH FROM lesson_sessions.created_at)) = #{current_month_first_day.month} ) )
|
||||
OR ((lesson_package_purchases.year = #{seven_days_in_future.year} AND lesson_package_purchases.month = #{seven_days_in_future.month}) AND ( (EXTRACT(YEAR FROM lesson_sessions.created_at)) = #{seven_days_in_future.year} AND (EXTRACT(MONTH FROM lesson_sessions.created_at)) = #{seven_days_in_future.month} ) ) )"
|
||||
else
|
||||
condition = "((lesson_package_purchases.year = #{current_month_first_day.year} AND lesson_package_purchases.month = #{current_month_first_day.month}) AND ( (EXTRACT(YEAR FROM lesson_sessions.created_at)) = #{current_month_first_day.year} AND (EXTRACT(MONTH FROM lesson_sessions.created_at)) = #{current_month_first_day.month} ) )"
|
||||
end
|
||||
|
||||
|
||||
# .where("(lesson_package_purchases.year = #{current_month_first_day.year} AND lesson_package_purchases.month = #{current_month_first_day.month}) OR (lesson_package_purchases.year = #{next_month_last_day.year} AND lesson_package_purchases.month = #{next_month_last_day.month})")
|
||||
|
||||
# find any monthly-billed bookings that have a session coming up within 7 days, and if so, attempt to bill them
|
||||
LessonBooking
|
||||
.joins(:lesson_sessions)
|
||||
.joins("LEFT JOIN lesson_package_purchases ON (lesson_package_purchases.lesson_booking_id = lesson_bookings.id AND #{condition})")
|
||||
.where("lesson_package_purchases.id IS NULL OR (lesson_package_purchases.id IS NOT NULL AND lesson_package_purchases.post_processed = false)")
|
||||
.where(payment_style: PAYMENT_STYLE_MONTHLY)
|
||||
.where(status: STATUS_APPROVED)
|
||||
.where('lesson_sessions.created_at >= ?', current_month_first_day)
|
||||
.where('lesson_sessions.created_at <= ?', seven_days_in_future).uniq
|
||||
|
||||
=end
|
||||
end
|
||||
|
||||
def self.bookings(student, teacher, since_at = nil)
|
||||
bookings = LessonBooking.where(user_id: student.id, teacher_id: teacher.id)
|
||||
|
||||
if since_at
|
||||
bookings = bookings.where('created_at >= ?', since_at)
|
||||
end
|
||||
|
||||
bookings
|
||||
end
|
||||
|
||||
def self.engaged_bookings(student, teacher, since_at = nil)
|
||||
bookings = bookings(student, teacher, since_at)
|
||||
bookings.engaged
|
||||
end
|
||||
|
||||
def bill_monthly(now)
|
||||
LessonBooking.transaction do
|
||||
self.lock!
|
||||
|
||||
current_month = Date.new(now.year, now.month, 1)
|
||||
|
||||
bill_for_month(current_month)
|
||||
|
||||
today = now.to_date
|
||||
seven_days_in_future = today + 7
|
||||
is_different_month = seven_days_in_future.month != today.month
|
||||
if is_different_month
|
||||
bill_for_month(seven_days_in_future)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def bill_for_month(day_in_month)
|
||||
# try to find lesson package purchase for this month, and last month, and see if they need processing
|
||||
current_month_purchase = lesson_package_purchases.where(lesson_booking_id: self.id, user_id: student.id, year: day_in_month.year, month: day_in_month.month).first
|
||||
if current_month_purchase.nil?
|
||||
current_month_purchase = LessonPackagePurchase.create(user, self, lesson_package_type, day_in_month.year, day_in_month.month)
|
||||
end
|
||||
current_month_purchase.bill_monthly
|
||||
end
|
||||
|
||||
def suspend!
|
||||
# when this is called, the calling code sends out a email to let the student and teacher know (it feels unnatural it's not here, though)
|
||||
self.status = STATUS_SUSPENDED
|
||||
self.active = false
|
||||
if self.save
|
||||
future_sessions.each do |lesson_session|
|
||||
LessonSession.find(lesson_session.id).suspend!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def unsuspend!
|
||||
if self.status == STATUS_SUSPENDED
|
||||
self.status = STATUS_APPROVED
|
||||
self.active = true
|
||||
if self.save
|
||||
future_sessions.each do |lesson_session|
|
||||
LessonSession.find(lesson_session.id).unsuspend!
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def future_sessions
|
||||
lesson_sessions.joins(:music_session).where('scheduled_start > ?', Time.now).order(:created_at)
|
||||
end
|
||||
|
||||
def self.schedule_upcoming_lessons
|
||||
minimum_start_time = (Time.now + APP_CONFIG.minimum_lesson_booking_hrs * 60*60)
|
||||
|
||||
lesson_bookings = find_bookings_needing_sessions(minimum_start_time)
|
||||
|
||||
lesson_bookings.each do |data|
|
||||
lesson_booking = LessonBooking.find(data["lesson_booking_id"])
|
||||
lesson_booking.sync_lessons
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def home_url
|
||||
APP_CONFIG.external_root_url + "/client#/jamclass"
|
||||
end
|
||||
|
||||
def web_url
|
||||
APP_CONFIG.external_root_url + "/client#/jamclass/lesson-booking/" + id
|
||||
end
|
||||
|
||||
def update_payment_url
|
||||
APP_CONFIG.external_root_url + "/client#/jamclass/update-payment"
|
||||
end
|
||||
|
||||
def admin_url
|
||||
APP_CONFIG.admin_root_url + "/admin/lesson_bookings/" + id
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,239 @@
|
|||
# represenst the type of lesson package
|
||||
module JamRuby
|
||||
class LessonBookingSlot < ActiveRecord::Base
|
||||
|
||||
include HtmlSanitize
|
||||
html_sanitize strict: [:message, :accept_message, :cancel_message]
|
||||
|
||||
@@log = Logging.logger[LessonBookingSlot]
|
||||
|
||||
belongs_to :lesson_booking, class_name: "JamRuby::LessonBooking"
|
||||
belongs_to :lesson_session, class_name: "JamRuby::LessonSession"
|
||||
belongs_to :proposer, class_name: "JamRuby::User"
|
||||
has_one :defaulted_booking, class_name: "JamRuby::LessonBooking", foreign_key: :default_slot_id, inverse_of: :default_slot
|
||||
has_one :countered_booking, class_name: "JamRuby::LessonBooking", foreign_key: :counter_slot_id, inverse_of: :counter_slot
|
||||
has_one :countered_lesson, class_name: "JamRuby::LessonSession", foreign_key: :counter_slot_id, inverse_of: :counter_slot
|
||||
|
||||
SLOT_TYPE_SINGLE = 'single'
|
||||
SLOT_TYPE_RECURRING = 'recurring'
|
||||
|
||||
SLOT_TYPES = [SLOT_TYPE_SINGLE, SLOT_TYPE_RECURRING]
|
||||
|
||||
validates :proposer, presence: true
|
||||
validates :slot_type, inclusion: {in: SLOT_TYPES}
|
||||
#validates :preferred_day
|
||||
validates :day_of_week, numericality: {only_integer: true}, allow_blank: true # 0 = sunday - 6 = saturday
|
||||
validates :hour, numericality: {only_integer: true}
|
||||
validates :minute, numericality: {only_integer: true}
|
||||
validates :timezone, presence: true # example: 'America/New_York'
|
||||
validates :update_all, inclusion: {in: [true, false]}
|
||||
|
||||
validate :validate_slot_type
|
||||
validate :validate_slot_minimum_time, on: :create
|
||||
validate :validate_proposer
|
||||
before_validation :before_validation
|
||||
|
||||
def before_validation
|
||||
if proposer.nil?
|
||||
self.proposer = container.student
|
||||
end
|
||||
end
|
||||
|
||||
def container
|
||||
if lesson_booking
|
||||
lesson_booking
|
||||
else
|
||||
lesson_session
|
||||
end
|
||||
end
|
||||
|
||||
def is_teacher_created?
|
||||
self.proposer == container.teacher
|
||||
end
|
||||
|
||||
def is_student_created?
|
||||
!is_teacher_created?
|
||||
end
|
||||
|
||||
def is_teacher_approved?
|
||||
!is_teacher_created?
|
||||
end
|
||||
|
||||
def recipient
|
||||
if is_teacher_created?
|
||||
container.student
|
||||
else
|
||||
container.teacher
|
||||
end
|
||||
end
|
||||
|
||||
def create_minimum_booking_time
|
||||
(Time.now + APP_CONFIG.minimum_lesson_booking_hrs * 60 * 60)
|
||||
end
|
||||
|
||||
def scheduled_times(needed_sessions, minimum_start_time)
|
||||
|
||||
times = []
|
||||
week_offset = 0
|
||||
|
||||
needed_sessions.times do |i|
|
||||
candidate = scheduled_time(i + week_offset)
|
||||
|
||||
if day_of_week && candidate <= minimum_start_time
|
||||
# move it up a week
|
||||
week_offset += 1
|
||||
candidate = scheduled_time(i + week_offset)
|
||||
|
||||
# sanity check
|
||||
if candidate <= minimum_start_time
|
||||
week_offset += 1
|
||||
candidate = scheduled_time(i + week_offset)
|
||||
|
||||
if candidate <= minimum_start_time
|
||||
raise "candidate time less than minimum start time even after scoot: #{lesson_booking.id} #{self.id}"
|
||||
end
|
||||
end
|
||||
end
|
||||
times << candidate
|
||||
end
|
||||
|
||||
times
|
||||
end
|
||||
|
||||
def next_day
|
||||
date = Date.today
|
||||
date += ((day_of_week - date.wday) % 7).abs
|
||||
end
|
||||
|
||||
# weeks is the number of weeks in the future to compute the time for
|
||||
def scheduled_time(weeks)
|
||||
|
||||
# get the timezone of the slot, so we can compute times
|
||||
tz = TZInfo::Timezone.get(timezone)
|
||||
|
||||
if preferred_day
|
||||
time = tz.local_to_utc(Time.new(preferred_day.year, preferred_day.month, preferred_day.day, hour, minute, 0))
|
||||
else
|
||||
adjusted = next_day + (weeks * 7)
|
||||
# day of the week adjustment
|
||||
time = tz.local_to_utc(Time.new(adjusted.year, adjusted.month, adjusted.day, hour, minute, 0))
|
||||
end
|
||||
|
||||
time
|
||||
end
|
||||
|
||||
def lesson_length
|
||||
safe_lesson_booking.lesson_length
|
||||
end
|
||||
|
||||
def safe_lesson_booking
|
||||
found = lesson_booking
|
||||
found ||= lesson_session.lesson_booking
|
||||
end
|
||||
|
||||
def pretty_scheduled_start(with_timezone = true)
|
||||
|
||||
start_time = scheduled_time(0)
|
||||
|
||||
begin
|
||||
tz = TZInfo::Timezone.get(timezone)
|
||||
rescue Exception => e
|
||||
@@log.error("unable to find timezone=#{tz_identifier}, e=#{e}")
|
||||
end
|
||||
|
||||
if tz
|
||||
begin
|
||||
start_time = tz.utc_to_local(start_time)
|
||||
rescue Exception => e
|
||||
@@log.error("unable to convert #{scheduled_start} to #{tz}, e=#{e}")
|
||||
puts "unable to convert #{e}"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
duration = lesson_length * 60 # convert from minutes to seconds
|
||||
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} #{tz}"
|
||||
else
|
||||
"#{start_time.strftime("%A, %B %e")} - #{start_time.strftime("%l:%M%P").strip}"
|
||||
end
|
||||
end
|
||||
|
||||
def pretty_start_time(with_timezone = true)
|
||||
|
||||
start_time = scheduled_time(0)
|
||||
|
||||
begin
|
||||
tz = TZInfo::Timezone.get(timezone)
|
||||
rescue Exception => e
|
||||
@@log.error("unable to find timezone=#{tz_identifier}, e=#{e}")
|
||||
end
|
||||
|
||||
if tz
|
||||
begin
|
||||
start_time = tz.utc_to_local(start_time)
|
||||
rescue Exception => e
|
||||
@@log.error("unable to convert #{scheduled_start} to #{tz}, e=#{e}")
|
||||
puts "unable to convert #{e}"
|
||||
end
|
||||
end
|
||||
|
||||
duration = lesson_length * 60 # convert from minutes to seconds
|
||||
end_time = start_time + duration
|
||||
if with_timezone
|
||||
"#{start_time.strftime("%a, %b %e")} at #{start_time.strftime("%l:%M%P").strip} #{tz.name}"
|
||||
else
|
||||
"#{start_time.strftime("%a, %b %e")} at #{start_time.strftime("%l:%M%P").strip}"
|
||||
end
|
||||
end
|
||||
|
||||
def validate_proposer
|
||||
if proposer && (proposer != container.student && proposer != container.teacher)
|
||||
errors.add(:proposer, "must be either the student or teacher")
|
||||
end
|
||||
end
|
||||
|
||||
def validate_slot_type
|
||||
if slot_type == SLOT_TYPE_SINGLE
|
||||
if preferred_day.nil?
|
||||
errors.add(:preferred_day, "must be specified")
|
||||
end
|
||||
end
|
||||
|
||||
if slot_type == SLOT_TYPE_RECURRING
|
||||
if day_of_week.nil?
|
||||
errors.add(:day_of_week, "must be specified")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def validate_slot_minimum_time
|
||||
|
||||
# this code will fail miserably if the slot is malformed
|
||||
if errors.any?
|
||||
return
|
||||
end
|
||||
|
||||
if is_teacher_created?
|
||||
return # the thinking is that a teacher can propose much tighter to the time; since they only counter; maybe they talked to the student
|
||||
end
|
||||
|
||||
#
|
||||
# minimum_start_time = create_minimum_booking_time
|
||||
minimum_start_time = Time.now
|
||||
|
||||
if day_of_week
|
||||
# this is recurring; it will sort itself out
|
||||
else
|
||||
time = scheduled_time(0)
|
||||
|
||||
if time <= minimum_start_time
|
||||
#errors.add(:base, "must be at least #{APP_CONFIG.minimum_lesson_booking_hrs} hours in the future")
|
||||
errors.add(:preferred_day, "can not be in the past")
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue