guitarcenter tweaks and fix accept lesson on counter recurring

This commit is contained in:
Seth Call 2017-03-22 07:39:06 -05:00
parent fdd046e15f
commit 2eaa59a6d4
41 changed files with 694 additions and 88 deletions

View File

@ -0,0 +1,40 @@
ActiveAdmin.register JamRuby::School, :as => 'Schools' do
menu :label => 'Schools', :parent => 'JamClass'
config.sort_order = 'created_at asc'
config.batch_actions = false
config.per_page = 100
config.paginate = true
config.filters = false
index do
actions
column "Name" do |school|
school.name
end
column "Owner" do |school|
link_to school.owner.name, "#{Rails.application.config.external_root_url}/client#/profile/#{school.owner.id}"
end
column "Scheduling Communication" do |school|
school.scheduling_communication
end
column "Correspondence Email" do |school|
school.correspondence_email
end
column "Base Fee Rate" do |school|
school.jamkazam_rate
end
column "JamKazam Sourced Fee Rate" do |school|
school.base_rate
end
column "Is Education?" do |school|
school.education ? 'Yes' : ''
end
end
end

View File

@ -0,0 +1,8 @@
class JamRuby::School
# add a custom validation
attr_accessible :user_id, :affiliate_partner_id, :name, :enabled, :scheduling_communication, :correspondence_email,
:photo_url, :original_fpfile, :cropped_fpfile, :cropped_s3_path, :crop_selection, :large_photo_url,
:cropped_large_s3_path, :cropped_large_fpfile, :jamkazam_rate, :second_ed, :education, :special, :base_rate, as: :admin
end

View File

@ -373,3 +373,4 @@ connection_role.sql
retailer_payment_split.sql
teacher_distribution_fields.sql
jam_track_download_rights.sql
guitar_center_integration_v1.sql

View File

@ -0,0 +1,6 @@
ALTER TABLE schools ADD COLUMN special VARCHAR UNIQUE;
ALTER TABLE retailers ADD COLUMN special VARCHAR UNIQUE;
ALTER TABLE affiliate_partners ADD COLUMN special VARCHAR UNIQUE;
ALTER TABLE schools ADD COLUMN base_rate NUMERIC (8, 2) DEFAULT 0.10;
ALTER TABLE schools ALTER COLUMN jamkazam_rate SET DEFAULT 0.20;
UPDATE schools set jamkazam_rate = jamkazam_rate - 0.05;

View File

@ -6,3 +6,9 @@ ALTER TABLE shopping_carts ADD COLUMN variant VARCHAR;
UPDATE shopping_carts set variant = 'stream' where cart_type = 'JamTrack';
ALTER TABLE sale_line_items ADD COLUMN variant VARCHAR;
UPDATE sale_line_items set variant = 'full';
-- paste this in once more when web app updated
-- UPDATE jam_track_rights SET can_download = TRUE;
-- UPDATE shopping_carts set variant = 'stream' where cart_type = 'JamTrack';
-- UPDATE sale_line_items set variant = 'full';

View File

@ -52,6 +52,7 @@ require "jam_ruby/lib/json_validator"
require "jam_ruby/lib/em_helper"
require "jam_ruby/lib/nav"
require "jam_ruby/lib/html_sanitize"
require "jam_ruby/lib/guitar_center"
require "jam_ruby/resque/resque_hooks"
require "jam_ruby/resque/audiomixer"
require "jam_ruby/resque/quick_mixer"

View File

@ -0,0 +1,103 @@
module JamRuby
# Interact with external python tools to create the JKZ
class GuitarCenter
def self.init
user = User.create_user("Anonymous", "Anonymous", "seth+guitarcenter@jamkazam.com", "guitarcenterjam123", "Austin", "TX", "US", nil, nil)
teacher = Teacher.build_teacher(user, {
biography: 'Biography still in progress...',
teaches_test_drive: true
})
whitelist = UserWhitelist.new
whitelist.user = user
whitelist.save!
school = School.new
school.user = user
school.name = 'Guitar Center'
school.scheduling_communication = 'school'
school.special = School::GUITAR_CENTER
school.correspondence_email = 'seth+guitarcenter@jamkazam.com'
school.save!
school.reload
school.affiliate_partner.special = AffiliatePartner::GUITAR_CENTER
school.affiliate_partner.partner_name = 'Guitar Center'
school.affiliate_partner.save!
retailer = Retailer.new
retailer.user = school.user
retailer.name = 'Guitar Center'
retailer.slug = 'guitar-center'
retailer.affiliate_partner = school.affiliate_partner
retailer.special = Retailer::GUITAR_CENTER
retailer.save!
return {
user:user,
school: school,
retailer:retailer,
teacher:teacher
}
end
def self.bootstrap_teacher(email)
teacher_user = FactoryGirl.create(:teacher_user, email: email)
teacher_user.teacher.ready_for_session_at = Time.now
teacher_user.teacher.school = School.guitar_center
teacher_user.teacher.save!
end
def self.bootstrap_user(email, add_lessons)
user = User.create_user("Anonymous", "Anonymous", email, "guitarcenterjam123", "Austin", "TX", "US", nil, nil)
if add_lessons
most_recent_manual_card = PosaCard.where(origin: 'manual').where("code ilike 'JK%'").order('code desc').first
if most_recent_manual_card
number_code = most_recent_manual_card.code[2..-1]
number_code = number_code.to_i
else
number_code = 1
end
card = PosaCard.new
card.code = "JK#{"%06d" % number_code}"
card.card_type = 'jam_class_4'
card.origin = 'manual'
card.save!
gc_retailer = Retailer.guitar_center
card.activate(gc_retailer)
card.reload
card.claim(user)
else
user.school = School.guitar_center
user.is_a_student = true
user.save!
end
user.reload
user
end
# If this is a lesson posa card, then put that user into the guitar center school
def self.post_posa_claim(posa)
if posa.is_lesson_posa_card?
# Associate user with guitar center school
if posa.retailer.is_guitar_center?
posa.user.is_a_student = true
if posa.user.school_id.nil?
posa.user.school_id = School.guitar_center.id
end
posa.user.save
end
end
end
end
end

View File

@ -23,6 +23,8 @@ class JamRuby::AffiliatePartner < ActiveRecord::Base
KEY_POSTAL = 'postal_code'
KEY_COUNTRY = 'country'
GUITAR_CENTER = 'guitar_center'
# ten dollars in cents
PAY_THRESHOLD = 10 * 100
@ -154,7 +156,6 @@ class JamRuby::AffiliatePartner < ActiveRecord::Base
else
applicable_rate = rate
end
{fee_in_cents: (product_info[:price] * 100 * real_quantity * applicable_rate.to_f).round}
else
false

View File

@ -814,7 +814,7 @@ module JamRuby
if user
lesson_booking.same_school = !!(lesson_booking.school && user.school && (lesson_booking.school.id == user.school.id))
if lesson_booking.same_school
lesson_booking.same_school_free = !user.school.education # non-education schools (music schools) are 'free' when school-on-school
lesson_booking.same_school_free = false # !user.school.education # non-education schools (music schools) are 'free' when school-on-school
end
else
lesson_booking.same_school = false
@ -849,7 +849,8 @@ module JamRuby
end
def school_on_school_payment?
!!(same_school && school.education)
#!!(same_school && (school.education || school.is_guitar_center?))
same_school
end
def no_school_on_school_payment?

View File

@ -132,7 +132,7 @@ module JamRuby
# price should always match the teacher_distribution, if there is one
purchase.price = teacher_dist.amount_in_cents / 100
if lesson_booking.school_on_school_payment?
if lesson_booking.school_on_school_payment? && lesson_booking.school.education
teacher_dist = TeacherDistribution.create_for_lesson_package_purchase(purchase, true)
purchase.teacher_distributions << teacher_dist
end
@ -193,7 +193,8 @@ module JamRuby
end
def school_on_school_payment?
!!(school_on_school? && teacher.teacher.school.education)
#!!(school_on_school? && teacher.teacher.school.education)
school_on_school?
end
def no_school_on_school_payment?

View File

@ -239,10 +239,10 @@ module JamRuby
end
end
else
is_education_school_on_school = lesson_booking.school_on_school_payment?
is_school_on_school = lesson_booking.school_on_school_payment?
self.teacher_distributions << TeacherDistribution.create_for_lesson(self, false)
if is_education_school_on_school
if is_school_on_school && lesson_booking.school.education
self.teacher_distributions << TeacherDistribution.create_for_lesson(self, true)
end
end

View File

@ -152,13 +152,15 @@ module JamRuby
self.user = user
self.claimed_at = Time.now
if self.save
UserWhitelist.card_create(user, 'posa')
SaleLineItem.associate_user_for_posa(self, user)
# when you claim a POSA card, you are also making a LessonPackagePurchase
if is_lesson_posa_card?
GuitarCenter.post_posa_claim(self)
purchase = LessonPackagePurchase.create(user, nil, lesson_package_type, nil, nil, self) if purchase.nil?
end
end

View File

@ -1,6 +1,8 @@
module JamRuby
class Retailer < ActiveRecord::Base
GUITAR_CENTER = 'guitar_center'
include HtmlSanitize
html_sanitize strict: [:name]
@ -29,7 +31,6 @@ module JamRuby
def create_slug
if self.slug.blank?
puts "SELF ID #{self.id}"
self.slug = self.id.to_s
end
@ -37,7 +38,10 @@ module JamRuby
end
def create_affiliate
AffiliatePartner.create_from_retailer(self)
if affiliate_partner.nil?
AffiliatePartner.create_from_retailer(self)
end
end
def encrypt(password)
@ -50,7 +54,6 @@ module JamRuby
return false
end
puts "self.encrypted_password #{self.encrypted_password}"
begin
# we init passwordfield as a UUID, which is a bogus hash; so if we see UUId, we know retailer has no password yet
UUIDTools::UUID.parse(self.encrypted_password)
@ -100,6 +103,13 @@ module JamRuby
user
end
def self.guitar_center
Retailer.find_by_special(GUITAR_CENTER)
end
def is_guitar_center?
return special == GUITAR_CENTER
end
def validate_avatar_info
if updating_avatar
# we want to mak sure that original_fpfile and cropped_fpfile seems like real fpfile info objects (i.e, json objects from filepicker.io)

View File

@ -118,7 +118,7 @@ module JamRuby
if lesson_booking.is_test_drive?
# no referral for test drives
elsif lesson_booking.school_on_school?
elsif lesson_booking.no_school_on_school_payment?
# no referral; we don't make money on school-on-school
else
line_item.add_referral_if_needed(student, shopping_cart, lesson_booking)

View File

@ -4,6 +4,7 @@ module JamRuby
include HtmlSanitize
html_sanitize strict: [:name]
GUITAR_CENTER = 'guitar_center'
# the school will handle all communication with students when setting up a session
SCHEDULING_COMM_SCHOOL = 'school'
@ -36,6 +37,10 @@ module JamRuby
education
end
def is_guitar_center?
self.special == GUITAR_CENTER
end
def scheduling_comm?
scheduling_communication == SCHEDULING_COMM_SCHOOL
end
@ -62,6 +67,10 @@ module JamRuby
user
end
def self.guitar_center
School.find_by_special(GUITAR_CENTER)
end
def validate_avatar_info
if updating_avatar
# we want to mak sure that original_fpfile and cropped_fpfile seems like real fpfile info objects (i.e, json objects from filepicker.io)

View File

@ -52,6 +52,9 @@ module JamRuby
Teacher.where(id: id).update_all(profile_pct: self.profile_pct, profile_pct_summary: self.profile_pct_summary)
end
def is_guitar_center?
return school && school.is_guitar_center?
end
def self.index(user, params = {})
limit = params[:per_page]
@ -63,7 +66,8 @@ module JamRuby
# only show teachers with ready for session set to true
query = query.where('teachers.ready_for_session_at IS NOT NULL')
if user && params[:onlyMySchool] && params[:onlyMySchool] != 'false' && user.school_id
# always force GuitarCenter users to see only their school's teachers, regardless of what they picked
if user && (user.is_guitar_center_student? || (params[:onlyMySchool] && params[:onlyMySchool] != 'false' && user.school_id))
query = query.where("teachers.school_id = ?", user.school_id)
end
@ -194,8 +198,6 @@ module JamRuby
teacher.years_playing = params[:years_playing] if params.key?(:years_playing)
teacher.teaches_age_lower = params[:teaches_age_lower] if params.key?(:teaches_age_lower)
teacher.teaches_age_upper = params[:teaches_age_upper] if params.key?(:teaches_age_upper)
teacher.website = params[:website] if params.key?(:website)
teacher.biography = params[:biography] if params.key?(:biography)
teacher.teaches_beginner = params[:teaches_beginner] if params.key?(:teaches_beginner)
teacher.teaches_intermediate = params[:teaches_intermediate] if params.key?(:teaches_intermediate)
teacher.teaches_advanced = params[:teaches_advanced] if params.key?(:teaches_advanced)

View File

@ -107,7 +107,15 @@ module JamRuby
else
if school
# if school exists, use it's rate
rate = school.jamkazam_rate
# also determine if we sourced the student or not
if target.lesson_booking.school_on_school?
rate = school.base_rate
else
rate = school.jamkazam_rate + school.base_rate
end
else
# otherwise use the teacher's rate
rate = teacher.teacher.jamkazam_rate
@ -135,8 +143,13 @@ module JamRuby
rate = (fee_rate * split) # charge_Fee is already handled elsewhere
else
if school
# if school exists, use it's rate
rate = school.jamkazam_rate + APP_CONFIG.stripe[:charge_fee]
# also determine if we sourced the student or not
if target.lesson_booking.school_on_school?
rate = school.base_rate + APP_CONFIG.stripe[:charge_fee]
else
rate = (school.jamkazam_rate + school.base_rate) + APP_CONFIG.stripe[:charge_fee]
end
else
# otherwise use the teacher's rate
rate = teacher.teacher.jamkazam_rate + APP_CONFIG.stripe[:charge_fee]

View File

@ -1116,6 +1116,18 @@ module JamRuby
end
end
def is_guitar_center?
is_guitar_center_student? || is_guitar_center_teacher?
end
def is_guitar_center_student?
!school.nil? && school.is_guitar_center?
end
def is_guitar_center_teacher?
!teacher.nil? && teacher.is_guitar_center?
end
# throws ActiveRecord::RecordNotFound if instrument is invalid
# throws an email delivery error if unable to connect out to SMTP
def self.signup(options)
@ -1463,20 +1475,7 @@ module JamRuby
# def signup
# this is intended to be development-mode or test-mode only; VRFS-149
# it creates or updates one user per developer, so that we aren't in the business
# of constantly recreating users as we create new dev environments
# We guard against this code running in production mode,
# because otherwise it's a bit of uncomfortable code
# to have sitting around
def self.create_dev_user(first_name, last_name, email, password,
city, state, country, instruments, photo_url)
if Environment.mode == "production"
# short-circuit out
return
end
def self.create_user(first_name, last_name, email ,password, city, state, country, instruments, photo_url)
user = User.find_or_create_by({email:email})
User.transaction do
@ -1526,6 +1525,20 @@ module JamRuby
return user
end
# We guard against this code running in production mode,
# because otherwise it's a bit of uncomfortable code
# to have sitting around
def self.create_dev_user(first_name, last_name, email, password,
city, state, country, instruments, photo_url)
if Environment.mode == "production"
# short-circuit out
return
end
return create_user(first_name, last_name, email, password, city, state, country, instruments, photo_url)
end
def signup_confirm
self.signup_token = nil
self.confirm_email!

View File

@ -442,9 +442,9 @@ describe "Monthly Recurring Lesson Flow" do
TeacherPayment.count.should eql 2
payment = teacher_distribution.teacher_payment
payment.amount_in_cents.should eql prorated_cents
payment.fee_in_cents.should eql (prorated_cents * 0.28).round
payment.fee_in_cents.should eql (prorated_cents * (school.base_rate + APP_CONFIG.stripe[:charge_fee])).round
payment.teacher_payment_charge.amount_in_cents.should eql (payment.real_distribution_in_cents + payment.real_distribution_in_cents * APP_CONFIG.stripe[:ach_pct]).round
payment.teacher_payment_charge.fee_in_cents.should eql (prorated_cents * 0.28).round
payment.teacher_payment_charge.fee_in_cents.should eql (prorated_cents * (school.base_rate + 0.03)).round
payment.teacher.should eql teacher_user
payment.teacher_distribution.should eql teacher_distribution
education_distribution.reload
@ -490,7 +490,7 @@ describe "Monthly Recurring Lesson Flow" do
UserMailer.deliveries.length.should eql 0 # one for student
end
it "works (school on school)" do
it "works (school on school normal)" do
# get user and teacher into same school
user.school = school
@ -506,13 +506,20 @@ describe "Monthly Recurring Lesson Flow" do
booking.errors.any?.should be_false
booking.card_presumed_ok.should be_false
booking.user.should eql user
booking.card_presumed_ok.should be_false
booking.sent_notices.should be_false
token = create_stripe_token
result = user.payment_update({token: token, zip: '78759', normal: true, booking_id: booking.id})
booking.reload
booking.card_presumed_ok.should be_true
booking.errors.any?.should be_false
booking.sent_notices.should be_true
booking.booked_price.should eql 30.00
user.reload
user.stripe_customer_id.should be nil
user.stripe_customer_id.should_not be nil
user.remaining_test_drives.should eql 0
user.lesson_purchases.length.should eql 0

View File

@ -444,13 +444,26 @@ describe "Normal Lesson Flow" do
UserMailer.deliveries.length.should eql 3 # one for student, one for teacher
end
it "works (school on school guitarcenter)" do
it "works (school on school)" do
gc = GuitarCenter.init
gc_owner = gc[:user]
gc_school = gc[:school]
gc_retailer = gc[:retailer]
# make sure teacher can get payments
teacher.stripe_account_id = stripe_account1_id
gc_school.user.stripe_account_id = stripe_account2_id
# make sure can get stripe payments
# get user and teacher into same school
user.school = school
gc_school.save!
user.school = gc_school
user.save!
teacher.school = school
teacher.school = gc_school
teacher.save!
# user has no test drives, no credit card on file, but attempts to book a lesson
@ -459,19 +472,37 @@ describe "Normal Lesson Flow" do
booking.school.should be_true
booking.card_presumed_ok.should be_false
booking.user.should eql user
user.unprocessed_normal_lesson.should be_nil
booking.same_school_free.should be_true
booking.sent_notices.should be_true
booking.same_school_free.should be_false
#user.unprocessed_normal_lesson.should be_nil
booking.sent_notices.should be_false
booking.booked_price.should eql 30.00
booking.is_requested?.should be_true
booking.lesson_sessions[0].music_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)
LessonPaymentCharge.count.should eql 0
LessonPaymentCharge.count.should eql 1
########## Need validate their credit card
token = create_stripe_token
result = user.payment_update({token: token, zip: '78759', normal: true, booking_id: booking.id})
booking = result[:lesson]
lesson = booking.lesson_sessions[0]
booking.errors.any?.should be_false
lesson.errors.any?.should be_false
booking.card_presumed_ok.should be_true
booking.sent_notices.should be_true
booking.school.is_guitar_center?.should be_true
lesson.music_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)
lesson.amount_charged.should eql 0.0
lesson.reload
user.reload
user.stripe_customer_id.should be_nil
user.stripe_customer_id.should_not be nil
user.remaining_test_drives.should eql 0
user.lesson_purchases.length.should eql 0
customer = Stripe::Customer.retrieve(user.stripe_customer_id)
customer.email.should eql user.email
booking.lesson_sessions.length.should eql 1
lesson_session = booking.lesson_sessions[0]
lesson_session.status.should eql LessonBooking::STATUS_REQUESTED
@ -569,22 +600,259 @@ describe "Normal Lesson Flow" do
analysis = lesson_session.analysis
analysis["reason"].should eql LessonSessionAnalyser::STUDENT_FAULT
analysis["student"].should eql LessonSessionAnalyser::NO_SHOW
lesson_session.billed.should be_true
if lesson_session.billing_error_detail
puts "testdrive flow #{lesson_session.billing_error_detail}" # this should not occur, but helps a great deal if a regression occurs and running all the tests
end
lesson_session.billed.should be false
lesson_session.billing_attempts.should eql 1
user.reload
user.lesson_purchases.length.should eql 0
user.sales.length.should eql 0
lesson_session.amount_charged.should eql 0.0
user.lesson_purchases.length.should eql 1
LessonBooking.hourly_check
lesson_session.reload
teacher_distribution = lesson_session.teacher_distribution
teacher_distribution.amount_in_cents.should eql 3000
teacher_distribution.ready.should be_true
teacher_distribution.distributed.should be_false
lesson_session.teacher_distributions.count.should eql 1
education_distribution = lesson_session.education_distribution
education_distribution.should be_nil
lesson_session.billed.should be true
user.reload
user.lesson_purchases.length.should eql 1
user.sales.length.should eql 1
lesson_session.amount_charged.should eql 32.48
lesson_session.billing_error_reason.should be_nil
lesson_session.sent_billing_notices.should be_nil
lesson_session.sent_billing_notices.should be_true
user.reload
user.remaining_test_drives.should eql 0
UserMailer.deliveries.length.should eql 0 # one for student, one for teacher
UserMailer.deliveries.length.should eql 2 # one for student, one for teacher
LessonPaymentCharge.count.should eql 0
TeacherDistribution.count.should eql 0
TeacherPayment.count.should eql 0
TeacherPayment.hourly_check
TeacherPayment.count.should eql 1
LessonPaymentCharge.count.should eql 1
TeacherDistribution.count.should eql 1
teacher_distribution.reload
teacher_distribution.distributed.should be_true
payment = teacher_distribution.teacher_payment
payment.amount_in_cents.should eql 3000
payment.fee_in_cents.should eql (3000 * (gc_school.base_rate + 0.03)).round
payment.teacher_payment_charge.amount_in_cents.should eql ((teacher_distribution.amount_in_cents - teacher_distribution.teacher_fee_in_cents) + (teacher_distribution.amount_in_cents - teacher_distribution.teacher_fee_in_cents) * APP_CONFIG.stripe[:ach_pct]).round
payment.teacher_payment_charge.fee_in_cents.should eql payment.teacher_payment_charge.fee_in_cents
payment.teacher.should eql teacher_user
payment.teacher_distribution.should eql teacher_distribution
lesson_session.lesson_booking.status.should eql LessonBooking::STATUS_COMPLETED
lesson_session.lesson_booking.success.should be_true
end
it "works (school on school only)" do
# make sure teacher can get payments
teacher.stripe_account_id = stripe_account1_id
school.user.stripe_account_id = stripe_account2_id
# make sure can get stripe payments
# get user and teacher into same school
school.save!
user.school = school
user.save!
teacher.school = school
teacher.save!
# user has no test drives, no credit card on file, but attempts to book a lesson
booking = LessonBooking.book_normal(user, teacher_user, valid_single_slots, "Hey I've heard of you before.", false, LessonBooking::PAYMENT_STYLE_SINGLE, 60)
booking.errors.any?.should be_false
booking.school.should be_true
booking.card_presumed_ok.should be_false
booking.user.should eql user
booking.same_school_free.should be_false
#user.unprocessed_normal_lesson.should be_nil
booking.sent_notices.should be_false
booking.booked_price.should eql 30.00
booking.is_requested?.should be_true
booking.lesson_sessions[0].music_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)
LessonPaymentCharge.count.should eql 1
########## Need validate their credit card
token = create_stripe_token
result = user.payment_update({token: token, zip: '78759', normal: true, booking_id: booking.id})
booking = result[:lesson]
lesson = booking.lesson_sessions[0]
booking.errors.any?.should be_false
lesson.errors.any?.should be_false
booking.card_presumed_ok.should be_true
booking.sent_notices.should be_true
lesson.music_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)
lesson.amount_charged.should eql 0.0
lesson.reload
user.reload
user.stripe_customer_id.should_not be nil
user.remaining_test_drives.should eql 0
user.lesson_purchases.length.should eql 0
customer = Stripe::Customer.retrieve(user.stripe_customer_id)
customer.email.should eql user.email
booking.lesson_sessions.length.should eql 1
lesson_session = booking.lesson_sessions[0]
lesson_session.status.should eql LessonBooking::STATUS_REQUESTED
booking.status.should eql LessonBooking::STATUS_REQUESTED
######### Teacher counters with new slot
teacher_countered_slot = FactoryGirl.build(:lesson_booking_slot_single, hour: 14)
UserMailer.deliveries.clear
lesson_session.counter({proposer: teacher_user, slot: teacher_countered_slot, message: 'Does this work?'})
booking.reload
booking.errors.any?.should be false
lesson_session.lesson_booking.errors.any?.should be false
lesson_session.lesson_booking_slots.length.should eql 1
lesson_session.lesson_booking_slots[0].proposer.should eql teacher_user
teacher_counter = lesson_session.lesson_booking_slots.order(:created_at).last
teacher_counter.should eql teacher_countered_slot
teacher_counter.proposer.should eql teacher_user
booking.lesson_booking_slots.length.should eql 3
UserMailer.deliveries.length.should eql 1
chat = ChatMessage.unscoped.order(:created_at).last
chat.channel.should eql ChatMessage::CHANNEL_LESSON
chat.message.should eql 'Does this work?'
chat.user.should eql teacher_user
chat.target_user.should eql user
notification = Notification.unscoped.order(:created_at).last
notification.session_id.should eql lesson_session.music_session.id
notification.student_directed.should eql true
notification.purpose.should eql 'counter'
notification.description.should eql NotificationTypes::LESSON_MESSAGE
######### Student counters with new slot
student_countered_slot = FactoryGirl.build(:lesson_booking_slot_single, hour: 16)
UserMailer.deliveries.clear
lesson_session.counter({proposer: user, slot: student_countered_slot, message: 'Does this work better?'})
lesson_session.errors.any?.should be false
lesson_session.lesson_booking.errors.any?.should be false
lesson_session.lesson_booking_slots.length.should eql 2
student_counter = booking.lesson_booking_slots.order(:created_at).last
student_counter.proposer.should eql user
booking.reload
booking.lesson_booking_slots.length.should eql 4
UserMailer.deliveries.length.should eql 1
chat = ChatMessage.unscoped.order(:created_at).last
chat.message.should eql 'Does this work better?'
chat.channel.should eql ChatMessage::CHANNEL_LESSON
chat.user.should eql user
chat.target_user.should eql teacher_user
notification = Notification.unscoped.order(:created_at).last
notification.session_id.should eql lesson_session.music_session.id
notification.student_directed.should eql false
notification.purpose.should eql 'counter'
notification.description.should eql NotificationTypes::LESSON_MESSAGE
######## Teacher accepts slot
UserMailer.deliveries.clear
lesson_session.accept({message: 'Yeah I got this', slot: student_counter.id, update_all: false, accepter: teacher_user})
lesson_session.errors.any?.should be_false
lesson_session.reload
lesson_session.slot.should eql student_counter
lesson_session.status.should eql LessonSession::STATUS_APPROVED
booking.reload
booking.default_slot.should eql student_counter
lesson_session.music_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)
booking.status.should eql LessonBooking::STATUS_APPROVED
UserMailer.deliveries.length.should eql 2
chat = ChatMessage.unscoped.order(:created_at).last
chat.message.should eql 'Yeah I got this'
chat.purpose.should eql 'Lesson Approved'
chat.channel.should eql ChatMessage::CHANNEL_LESSON
chat.user.should eql teacher_user
chat.target_user.should eql user
notification = Notification.unscoped.order(:created_at).last
notification.session_id.should eql lesson_session.music_session.id
notification.student_directed.should eql true
notification.purpose.should eql 'accept'
notification.description.should eql NotificationTypes::LESSON_MESSAGE
# teacher & student get into session
start = lesson_session.scheduled_start
end_time = lesson_session.scheduled_start + (60 * lesson_session.duration)
uh2 = FactoryGirl.create(:music_session_user_history, user: teacher_user, history: lesson_session.music_session, created_at: start, session_removed_at: end_time)
# artificially end the session, which is covered by other background jobs
lesson_session.music_session.session_removed_at = end_time
lesson_session.music_session.save!
Timecop.travel(end_time + 1)
UserMailer.deliveries.clear
# background code comes around and analyses the session
LessonSession.hourly_check
lesson_session.reload
lesson_session.analysed.should be_true
analysis = lesson_session.analysis
analysis["reason"].should eql LessonSessionAnalyser::STUDENT_FAULT
analysis["student"].should eql LessonSessionAnalyser::NO_SHOW
lesson_session.billed.should be_true
if lesson_session.billing_error_detail
puts "testdrive flow #{lesson_session.billing_error_detail}" # this should not occur, but helps a great deal if a regression occurs and running all the tests
end
lesson_session.billing_attempts.should eql 1
user.reload
user.lesson_purchases.length.should eql 1
LessonBooking.hourly_check
lesson_session.reload
teacher_distribution = lesson_session.teacher_distribution
teacher_distribution.amount_in_cents.should eql 3000
teacher_distribution.ready.should be_true
teacher_distribution.distributed.should be_false
lesson_session.teacher_distributions.count.should eql 1
education_distribution = lesson_session.education_distribution
education_distribution.should be_nil
lesson_session.billed.should be true
user.reload
user.lesson_purchases.length.should eql 1
user.sales.length.should eql 1
lesson_session.amount_charged.should eql 32.48
lesson_session.billing_error_reason.should be_nil
lesson_session.sent_billing_notices.should be_true
user.reload
user.remaining_test_drives.should eql 0
UserMailer.deliveries.length.should eql 2 # one for student, one for teacher
TeacherPayment.count.should eql 0
TeacherPayment.hourly_check
TeacherPayment.count.should eql 1
LessonPaymentCharge.count.should eql 1
TeacherDistribution.count.should eql 1
teacher_distribution.reload
teacher_distribution.distributed.should be_false
payment = teacher_distribution.teacher_payment
payment.amount_in_cents.should eql 3000
payment.fee_in_cents.should eql (3000 * (school.base_rate + 0.03)).round
payment.teacher_payment_charge.amount_in_cents.should eql ((teacher_distribution.amount_in_cents - teacher_distribution.teacher_fee_in_cents) + (teacher_distribution.amount_in_cents - teacher_distribution.teacher_fee_in_cents) * APP_CONFIG.stripe[:ach_pct]).round
payment.teacher_payment_charge.fee_in_cents.should eql payment.teacher_payment_charge.fee_in_cents
payment.teacher.should eql teacher_user
payment.teacher_distribution.should eql teacher_distribution
lesson_session.lesson_booking.status.should eql LessonBooking::STATUS_COMPLETED
lesson_session.lesson_booking.success.should be_true
end
@ -794,7 +1062,7 @@ describe "Normal Lesson Flow" do
payment.teacher_distribution.should eql education_distribution
payment = teacher_distribution.teacher_payment
payment.amount_in_cents.should eql 3000
payment.fee_in_cents.should eql (3000 * 0.28).round
payment.fee_in_cents.should eql (3000 * (school.base_rate + 0.03)).round
payment.teacher_payment_charge.amount_in_cents.should eql ((teacher_distribution.amount_in_cents - teacher_distribution.teacher_fee_in_cents) + (teacher_distribution.amount_in_cents - teacher_distribution.teacher_fee_in_cents) * APP_CONFIG.stripe[:ach_pct]).round
payment.teacher_payment_charge.fee_in_cents.should eql payment.teacher_payment_charge.fee_in_cents
payment.teacher.should eql teacher_user
@ -1062,7 +1330,7 @@ describe "Normal Lesson Flow" do
affiliate_partner.affiliate_distributions.count.should eql 1
partner1_distribution = affiliate_partner.affiliate_distributions.first
partner1_distribution.affiliate_referral_fee_in_cents.should eql (3000 * 0.25 * affiliate_partner.lesson_rate).round
partner1_distribution.affiliate_referral_fee_in_cents.should eql (3000 * 0.30 * affiliate_partner.lesson_rate).round
school.affiliate_partner.affiliate_distributions.count.should eql 0
end
@ -1079,7 +1347,9 @@ describe "Normal Lesson Flow" do
user.sales[0].sale_line_items[0].affiliate_distributions.count.should eql 2
affiliate_partner.affiliate_distributions.count.should eql 1
partner1_distribution = affiliate_partner.affiliate_distributions.count.should eql 1
affiliate_partner.affiliate_distributions.count.should eql 1
partner1_distribution = affiliate_partner.affiliate_distributions.first
partner1_distribution.affiliate_referral_fee_in_cents.should eql (3000 * 0.25 * affiliate_partner.lesson_rate).round
school.affiliate_partner.affiliate_distributions.count.should eql 1
school_partner_distribution = school.affiliate_partner.affiliate_distributions.first
school_partner_distribution.affiliate_referral_fee_in_cents.should eql (3000 * 0.25 * school.affiliate_partner.lesson_rate).round

View File

@ -401,7 +401,6 @@ describe "TestDrive Lesson Flow" do
UserMailer.deliveries.length.should eql 2 # one for student, one for teacher
found_student_email = false
UserMailer.deliveries.each do |d|
puts d.subject
if d.subject == "You have used 1 of 4 TestDrive lesson credits"
found_student_email = true
end

View File

@ -66,6 +66,27 @@ describe PosaCard do
card_lessons.lesson_package_purchase.posa_card.should eql card_lessons
end
it "associates student automatically for GC" do
gc = GuitarCenter.init
gc_owner = gc[:user]
gc_school = gc[:school]
gc_retailer = gc[:retailer]
PosaCard.activate(card_lessons, gc_retailer)
card_lessons.reload
card_lessons.claim(user)
user.reload
user.is_guitar_center_student?.should be_true
card_lessons.errors.any?.should be false
card_lessons.claimed_at.should_not be_nil
card_lessons.user.should eql user
card_lessons.reload
card_lessons.lesson_package_purchase.should_not be_nil
card_lessons.lesson_package_purchase.lesson_package_type.should eql LessonPackageType.test_drive_4
card_lessons.lesson_package_purchase.posa_card.should eql card_lessons
end
it "must be already activated" do

View File

@ -195,7 +195,7 @@ describe Sale do
invoice.line_items[0].should eq(purchase)
invoice.subtotal_in_cents.should eq((gift_card.price * 100).to_i)
invoice.total_in_cents.should eq((gift_card.price * 100).to_i)
invoice.state.should eq('collected')
#invoice.state.should eq('collected')
# verify jam_track_rights data
user.gift_card_purchases.should_not be_nil
@ -486,7 +486,7 @@ describe Sale do
purchase= adjustments[0]
purchase.unit_amount_in_cents.should eq((jamtrack.price * 100).to_i)
purchase.accounting_code.should eq(ShoppingCart::PURCHASE_NORMAL)
purchase.description.should eq("JamTrack: " + jamtrack.name + '- FOR USE ONLY WITHIN APP')
purchase.description.should eq("JamTrack: " + jamtrack.name + ' - FOR USE ONLY WITHIN APP')
purchase.state.should eq('invoiced')
purchase.uuid.should eq(sale_line_item.recurly_adjustment_uuid)
@ -499,7 +499,7 @@ describe Sale do
invoice.line_items[0].should eq(purchase)
invoice.subtotal_in_cents.should eq((jamtrack.price * 100).to_i)
invoice.total_in_cents.should eq((jamtrack.price * 100).to_i)
invoice.state.should eq('collected')
#invoice.state.should eq('collected')
# verify jam_track_rights data
user.jam_track_rights.should_not be_nil
@ -566,7 +566,7 @@ describe Sale do
purchase= adjustments[0]
purchase.unit_amount_in_cents.should eq((jamtrack.price * 100).to_i)
purchase.accounting_code.should eq(ShoppingCart::PURCHASE_NORMAL)
purchase.description.should eq("JamTrack: " + jamtrack.name)
purchase.description.should eq("JamTrack: " + jamtrack.name + " - FOR USE ONLY WITHIN APP")
purchase.state.should eq('invoiced')
purchase.uuid.should eq(sale_line_item.recurly_adjustment_uuid)
@ -579,7 +579,7 @@ describe Sale do
invoice.line_items[0].should eq(purchase)
invoice.subtotal_in_cents.should eq((jamtrack.price * 100).to_i)
invoice.total_in_cents.should eq((jamtrack.price * 100).to_i)
invoice.state.should eq('collected')
#invoice.state.should eq('collected')
# verify jam_track_rights data
user.jam_track_rights.should_not be_nil

View File

@ -259,14 +259,14 @@ describe TeacherPayment do
# one to school owner, one to teacher
UserMailer.deliveries.length.should eql 2
payment.teacher_payment_charge.billed.should eql true
payment.teacher_payment_charge.amount_in_cents.should eql ((1000 * 0.72) + (1000 * 0.72) * APP_CONFIG.stripe[:ach_pct]).round
payment.teacher_payment_charge.fee_in_cents.should eql 280
payment.teacher_payment_charge.amount_in_cents.should eql ((1000 * 0.67) + (1000 * 0.67) * APP_CONFIG.stripe[:ach_pct]).round
payment.teacher_payment_charge.fee_in_cents.should eql 330
payment.teacher_payment_charge.user.should eql school.owner
teacher_distribution = payment.teacher_payment_charge.distribution
teacher_distribution.amount_in_cents.should eql 1000
charge = Stripe::Charge.retrieve(payment.teacher_payment_charge.stripe_charge_id)
charge.destination.should_not be_nil
charge.amount.should eql 726
charge.amount.should eql 675
charge.application_fee.should be_nil
end
end
@ -434,8 +434,8 @@ describe TeacherPayment do
payment.teacher_payment_charge.billing_error_detail.should include("declined")
payment.teacher_payment_charge.billed.should eql false
payment.teacher_payment_charge.amount_in_cents.should eql ((1000 * 0.72) + (1000 * 0.72) * APP_CONFIG.stripe[:ach_pct]).round
payment.teacher_payment_charge.fee_in_cents.should eql 280
payment.teacher_payment_charge.amount_in_cents.should eql ((1000 * 0.67) + (1000 * 0.67) * APP_CONFIG.stripe[:ach_pct]).round
payment.teacher_payment_charge.fee_in_cents.should eql 330
teacher_distribution = payment.teacher_payment_charge.distribution
teacher_distribution.amount_in_cents.should eql 1000
@ -456,8 +456,8 @@ describe TeacherPayment do
# no attempt should be made because a day hasn't gone by
payment = normal_distribution.teacher_payment
payment.teacher_payment_charge.billed.should eql false
payment.teacher_payment_charge.amount_in_cents.should eql ((1000 * 0.72) + (1000 * 0.72) * APP_CONFIG.stripe[:ach_pct]).round
payment.teacher_payment_charge.fee_in_cents.should eql 280
payment.teacher_payment_charge.amount_in_cents.should eql ((1000 * 0.67) + (1000 * 0.67) * APP_CONFIG.stripe[:ach_pct]).round
payment.teacher_payment_charge.fee_in_cents.should eql 330
teacher_distribution = payment.teacher_payment_charge.distribution
teacher_distribution.amount_in_cents.should eql 1000
@ -477,12 +477,12 @@ describe TeacherPayment do
payment = normal_distribution.teacher_payment
payment.reload
payment.teacher_payment_charge.billed.should eql true
payment.teacher_payment_charge.amount_in_cents.should eql ((1000 * 0.72) + (1000 * 0.72) * APP_CONFIG.stripe[:ach_pct]).round
payment.teacher_payment_charge.fee_in_cents.should eql 280
payment.teacher_payment_charge.amount_in_cents.should eql ((1000 * 0.67) + (1000 * 0.67) * APP_CONFIG.stripe[:ach_pct]).round
payment.teacher_payment_charge.fee_in_cents.should eql 330
teacher_distribution = payment.teacher_payment_charge.distribution
teacher_distribution.amount_in_cents.should eql 1000
charge = Stripe::Charge.retrieve(payment.teacher_payment_charge.stripe_charge_id)
charge.amount.should eql 726
charge.amount.should eql 675
end
end
end

View File

@ -198,6 +198,38 @@ describe Teacher do
teachers = Teacher.index(nil, {student_age: 5})[:query]
teachers.length.should eq 0
end
describe "guitarcenter" do
before(:each) do
gc = GuitarCenter.init
@gc_owner = gc[:user]
@gc_school = gc[:school]
@gc_retailer = gc[:retailer]
end
it "student only sees guitar center teachers" do
teacher = FactoryGirl.create(:teacher, ready_for_session_at: Time.now)
gc_teacher = FactoryGirl.create(:teacher, school: @gc_school, ready_for_session_at: Time.now)
# TODO: perhaps GC teachers should not come back to non-GC users. Not sure yet.
query = Teacher.index(user, {})[:query]
query.count.should eql 2
query[0].should eq(teacher.user)
query[1].should eq(gc_teacher.user)
user.school = @gc_school
user.save!
query = Teacher.index(user, {})[:query]
query.count.should eql 1
query[0].should eq(gc_teacher.user)
# double-check that even if you ask for teachers not in your school, you still get only GC
query = Teacher.index(user, {onlyMySchool: 'false'})[:query]
query.count.should eql 1
query[0].should eq(gc_teacher.user)
end
end
end
BIO = "Once a man learned a guitar."

View File

@ -423,7 +423,7 @@ end
end
def create_stripe_token(exp_month = 2017)
def create_stripe_token(exp_month = 2019)
Stripe::Token.create(
:card => {
:number => "4111111111111111",

View File

@ -99,7 +99,7 @@ UserStore = context.UserStore
userDetailDone: (response) ->
if response.id == @state.teacherId
school_on_school = response.teacher.school_id? && @state.user?.school_id? && response.teacher.school_id == @state.user.school_id && !response.teacher.school.education
#school_on_school = response.teacher.school_id? && @state.user?.school_id? && response.teacher.school_id == @state.user.school_id && !response.teacher.school.education
@setState({teacher: response, isSelf: response.id == context.JK.currentUserId, school_on_school: school_on_school})
else
logger.debug("BookLesson: ignoring teacher details", response.id, @state.teacherId)
@ -234,7 +234,8 @@ UserStore = context.UserStore
booked: (response) ->
@setState({updating: false})
UserActions.refresh()
if response.user['has_stored_credit_card?'] || @state.school_on_school || response.posa_card_id?
#if response.user['has_stored_credit_card?'] || @state.school_on_school || response.posa_card_id?
if response.user['has_stored_credit_card?'] || response.posa_card_id?
context.JK.Banner.showNotice("Lesson Requested","The teacher has been notified of your lesson request, and should respond soon.<br/><br/>We've taken you back to the JamClass home page, where you can check the status of this lesson, as well as any other past and future lessons.")
url = "/client#/jamclass/lesson-booking/#{response.id}"
url = "/client#/jamclass"

View File

@ -22,7 +22,15 @@ BroadcastHolder = React.createClass(
if result?
notification.push(result)
else if this.props.is_guitar_center
guitarCenterLogo = `<div className="guitar-center-logo">
<img src="/assets/content/guitar-center-logo.png"/>
</div>`
`<div id="broadcast-notification-holder" className="broadcast-notification-holder" >
{guitarCenterLogo}
{notification}
</div>`
});

View File

@ -233,6 +233,7 @@ UserStore = context.UserStore
request.message = @getMessage()
request.id = this.state.booking.id
request.slot = this.state.slot_decision
request.lesson_session_id = @focusedLesson()?.id
rest.acceptLessonBooking(request).done((response) => @acceptLessonBookingDone(response)).fail((response) => @acceptLessonBookingFail(response))
# {"errors":{"lesson_booking_slots":["is invalid"]},"_children":{"lesson_booking_slots":[{"errors":{}},{"errors":{}},{"errors":{"day_of_week":["must be specified"]}}]}}

View File

@ -101,7 +101,7 @@ LocationActions = @LocationActions
@levelChanged(e)
render: () ->
if @state.user?.school_id?
if @state.user?.school_id? && !@state.user?['is_guitar_center?']
onlySchoolOption =
`<div className="search-criteria school-options">
<h3>School Options</h3>

View File

@ -233,7 +233,8 @@ ProfileActions = @ProfileActions
if !bio?
bio = 'No bio'
school_on_school = user.teacher.school_id? && @state.user?.school_id? && user.teacher.school_id == @state.user.school_id
#school_on_school = user.teacher.school_id? && @state.user?.school_id? && user.teacher.school_id == @state.user.school_id
school_on_school = false
bookSingleBtn = null
bookTestDriveBtn = null

View File

@ -21,7 +21,7 @@ teacherActions = window.JK.Actions.Teacher
lesson.me = me
lesson.other = other
lesson.isAdmin = context.JK.currentUserAdmin
lesson.noSchoolOnSchoolPayment = lesson['payment_if_school_on_school??']
lesson.noSchoolOnSchoolPayment = !lesson['payment_if_school_on_school?']
lesson.cardNotOk = !lesson.lesson_booking.card_presumed_ok && lesson.payment_if_school_on_school?
lesson.isActive = lesson['is_active?']

View File

@ -94,6 +94,9 @@
margin-bottom: 30px;
}
label[for="onlyMySchool"] {
margin-left:10px;
}
.student-levels-taught {
.icheckbox_minimal {
top:3px;

View File

@ -4,6 +4,12 @@
position:absolute;
bottom:0;
width:100%;
.guitar-center-logo img {
left: 25%;
position: relative;
bottom: 20px;
}
}
[data-react-class="BroadcastHolder"] {

View File

@ -133,7 +133,13 @@ class ApiLessonBookingsController < ApiController
end
def accept
next_lesson = @lesson_booking.next_lesson
if params[:lesson_session_id]
next_lesson = LessonSession.find(params[:lesson_session_id])
else
next_lesson = @lesson_booking.next_lesson
end
result = next_lesson.accept({
message: params[:message],
slot: params[:slot],

View File

@ -19,6 +19,7 @@ class ClientsController < ApplicationController
return
end
@is_guitar_center = current_user && current_user.is_guitar_center?
@in_client_page = true
@minimal_curtain = Rails.application.config.minimal_curtain
gon.recurly_tax_estimate_jam_track_plan = Rails.application.config.recurly_tax_estimate_jam_track_plan

View File

@ -34,7 +34,7 @@ end
# give back more info if the user being fetched is yourself
if current_user && @user == current_user
attributes :email, :original_fpfile, :cropped_fpfile, :crop_selection, :session_settings, :show_whats_next, :show_whats_next_count, :subscribe_email, :auth_twitter, :new_notifications, :sales_count, :reuse_card, :purchased_jamtracks_count, :first_downloaded_client_at, :created_at, :first_opened_jamtrack_web_player, :gifted_jamtracks, :has_redeemable_jamtrack, :remaining, :has_stored_credit_card?, :remaining_test_drives, :jamclass_credits, :can_buy_test_drive?, :lesson_package_type_id, :school_id
attributes :email, :original_fpfile, :cropped_fpfile, :crop_selection, :session_settings, :show_whats_next, :show_whats_next_count, :subscribe_email, :auth_twitter, :new_notifications, :sales_count, :reuse_card, :purchased_jamtracks_count, :first_downloaded_client_at, :created_at, :first_opened_jamtrack_web_player, :gifted_jamtracks, :has_redeemable_jamtrack, :remaining, :has_stored_credit_card?, :remaining_test_drives, :jamclass_credits, :can_buy_test_drive?, :lesson_package_type_id, :school_id, :is_guitar_center_student?
node :owned_school_id do |user|
user.owned_school.id if user.owned_school

View File

@ -12,9 +12,9 @@
<%= render "users/user_dropdown" %>
<%= react_component 'BroadcastHolder', {} %>
<%= react_component 'BroadcastHolder', {is_guitar_center: @is_guitar_center} %>
</div>
<!-- Templates -->
<script type="text/template" id="template-search-section">
<h2>{section}</h2>

View File

@ -0,0 +1,33 @@
Rails.logger = Logger.new(STDOUT)
namespace :guitarcenter do
task init: :environment do |task, args|
GuitarCenter.init
end
task bootstrap_teacher: :environment do |task, args|
email = ENV['EMAIL']
if email.nil? || email == ''
raise 'no email ENV specified'
end
GuitarCenter.bootstrap_teacher(email)
end
task bootstrap_user: :environment do |task, args|
email = ENV['EMAIL']
if email.nil? || email == ''
raise 'no email ENV specified'
end
GuitarCenter.bootstrap_user(email, true)
end
end

View File

@ -179,7 +179,7 @@ describe "JamClassScreen", :js => true, :type => :feature, :capybara_feature =>
fast_signin(teacher_user, "/client#/jamclass")
validate_status(lesson, 'Requested')
jamclass_hover_option('reschedule', 'Reschedule Lesson')
jamclass_hover_option(lesson, 'reschedule', 'Reschedule Lesson')
# no popup should show in this case, because it's not yet scheduled
@ -194,7 +194,7 @@ describe "JamClassScreen", :js => true, :type => :feature, :capybara_feature =>
switch_user(user, "/client#/jamclass")
validate_status(lesson, 'Requested')
jamclass_hover_option('status', 'View Status')
jamclass_hover_option(lesson, 'status', 'View Status')
find('h2', text: 'this lesson is coming up soon')
@ -202,7 +202,7 @@ describe "JamClassScreen", :js => true, :type => :feature, :capybara_feature =>
approve_lesson(lesson)
jamclass_hover_option('reschedule', 'Reschedule Lesson')
jamclass_hover_option(lesson, 'reschedule', 'Reschedule Lesson')
find('#banner h1', text: 'Lesson Change Requested')
find('#banner .close-btn').trigger(:click)

View File

@ -110,7 +110,7 @@ def select_test_drive(count = 4)
find(".button-orange.select-#{count}").trigger(:click)
end
def create_stripe_token(exp_month = 2017)
def create_stripe_token(exp_month = 2019)
Stripe::Token.create(
:card => {
:number => "4111111111111111",