mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2025-03-14 07:00:01 -04:00
Purchase prepaid on course instance creation
Updating purchase prepaid API to support courses. Refactoring the prepaid server code. Completes #54270567235517
This commit is contained in:
parent
079e3a59f5
commit
5095eac4ac
10 changed files with 553 additions and 351 deletions
|
@ -199,9 +199,9 @@ module.exports.getSponsoredSubsAmount = getSponsoredSubsAmount = (price=999, sub
|
|||
else
|
||||
Math.round((1 - offset) * price + 10 * price * 0.8 + (subCount - 11 + offset) * price * 0.6)
|
||||
|
||||
module.exports.getCoursesPrice = getSponsoredSubsAmount = (courses, seats=20) ->
|
||||
totalPricePerSeat = courses.reduce ((a, b) -> a + b.get('pricePerSeat')), 0
|
||||
if courses.length > 2
|
||||
module.exports.getCourseBundlePrice = getCourseBundlePrice = (coursePrices, seats=20) ->
|
||||
totalPricePerSeat = coursePrices.reduce ((a, b) -> a + b), 0
|
||||
if coursePrices.length > 2
|
||||
pricePerSeat = Math.round(totalPricePerSeat / 2.0)
|
||||
else
|
||||
pricePerSeat = parseInt(totalPricePerSeat)
|
||||
|
|
|
@ -39,7 +39,7 @@ block content
|
|||
label.control-label.col-md-2(data-i18n="account_prepaid.purchase_total")
|
||||
.col-md-10
|
||||
p.form-control-static $
|
||||
span#total #{purchase.total}
|
||||
span#total #{purchase.total.toFixed(2)}
|
||||
button#purchase-button.btn.btn-success.pull-right(data-i18n="account_prepaid.purchase_button")
|
||||
.row
|
||||
.col-md-12
|
||||
|
|
|
@ -2,10 +2,10 @@ app = require 'core/application'
|
|||
AuthModal = require 'views/core/AuthModal'
|
||||
CocoCollection = require 'collections/CocoCollection'
|
||||
Course = require 'models/Course'
|
||||
{getCoursesPrice} = require 'core/utils'
|
||||
RootView = require 'views/core/RootView'
|
||||
stripeHandler = require 'core/services/stripe'
|
||||
template = require 'templates/courses/course-enroll'
|
||||
utils = require 'core/utils'
|
||||
|
||||
module.exports = class CourseEnrollView extends RootView
|
||||
id: 'course-enroll-view'
|
||||
|
@ -101,7 +101,9 @@ module.exports = class CourseEnrollView extends RootView
|
|||
data =
|
||||
name: @className
|
||||
seats: @seats
|
||||
token: token
|
||||
stripe:
|
||||
token: token
|
||||
timestamp: new Date().getTime()
|
||||
data.courseID = @selectedCourse.id if @selectedCourse
|
||||
jqxhr = $.post('/db/course_instance/-/create', data)
|
||||
jqxhr.done (data, textStatus, jqXHR) =>
|
||||
|
@ -109,9 +111,14 @@ module.exports = class CourseEnrollView extends RootView
|
|||
# TODO: handle fetch errors
|
||||
me.fetch(cache: false).always =>
|
||||
courseID = @selectedCourse?.id ? @courses.models[0]?.id
|
||||
viewArgs = if data?.length > 0 then [courseInstanceID: data[0]._id, courseID] else [{}, courseID]
|
||||
route = "/courses/#{courseID}"
|
||||
viewArgs = [{}, courseID]
|
||||
if data?.length > 0
|
||||
courseInstanceID = data[0]._id
|
||||
route += "/#{courseInstanceID}"
|
||||
viewArgs[0].courseInstanceID = courseInstanceID
|
||||
Backbone.Mediator.publish 'router:navigate',
|
||||
route: "/courses/#{courseID}"
|
||||
route: route
|
||||
viewClass: 'views/courses/CourseDetailsView'
|
||||
viewArgs: viewArgs
|
||||
jqxhr.fail (xhr, textStatus, errorThrown) =>
|
||||
|
@ -127,7 +134,8 @@ module.exports = class CourseEnrollView extends RootView
|
|||
|
||||
renderNewPrice: ->
|
||||
if @selectedCourse
|
||||
@price = getCoursesPrice([@selectedCourse], @seats)
|
||||
coursePrices = [@selectedCourse.get('pricePerSeat')]
|
||||
else
|
||||
@price = getCoursesPrice(@courses.models, @seats)
|
||||
coursePrices = (c.get('pricePerSeat') for c in @courses.models)
|
||||
@price = utils.getCourseBundlePrice(coursePrices, @seats)
|
||||
@render?()
|
||||
|
|
|
@ -61,6 +61,7 @@ module.exports = class CoursesView extends RootView
|
|||
application.tracker?.trackEvent 'Subscription payment methods hover'
|
||||
|
||||
onClickBuy: (e) ->
|
||||
$('.continue-dialog').modal('hide')
|
||||
courseID = $(e.target).data('course-id')
|
||||
route = "/courses/enroll/#{courseID}"
|
||||
viewClass = require 'views/courses/CourseEnrollView'
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
async = require 'async'
|
||||
Handler = require '../commons/Handler'
|
||||
{getCoursesPrice} = require '../../app/core/utils'
|
||||
Course = require './Course'
|
||||
CourseInstance = require './CourseInstance'
|
||||
LevelSession = require '../levels/sessions/LevelSession'
|
||||
LevelSessionHandler = require '../levels/sessions/level_session_handler'
|
||||
Prepaid = require '../prepaids/Prepaid'
|
||||
PrepaidHandler = require '../prepaids/prepaid_handler'
|
||||
User = require '../users/User'
|
||||
UserHandler = require '../users/user_handler'
|
||||
utils = require '../../app/core/utils'
|
||||
|
||||
CourseInstanceHandler = class CourseInstanceHandler extends Handler
|
||||
modelClass: CourseInstance
|
||||
|
@ -15,7 +16,7 @@ CourseInstanceHandler = class CourseInstanceHandler extends Handler
|
|||
allowedMethods: ['GET', 'POST', 'PUT', 'DELETE']
|
||||
|
||||
logError: (user, msg) ->
|
||||
console.warn "Course error: #{user.get('slug')} (#{user._id}): '#{msg}'"
|
||||
console.warn "Course instance error: #{user.get('slug')} (#{user._id}): '#{msg}'"
|
||||
|
||||
hasAccess: (req) ->
|
||||
req.method in @allowedMethods or req.user?.isAdmin()
|
||||
|
@ -33,7 +34,7 @@ CourseInstanceHandler = class CourseInstanceHandler extends Handler
|
|||
super arguments...
|
||||
|
||||
createAPI: (req, res) ->
|
||||
return @sendUnauthorizedError(res) unless req.user?
|
||||
return @sendUnauthorizedError(res) if not req.user? or req.user?.isAnonymous()
|
||||
|
||||
# Required Input
|
||||
seats = req.body.seats
|
||||
|
@ -45,43 +46,30 @@ CourseInstanceHandler = class CourseInstanceHandler extends Handler
|
|||
# Optional
|
||||
name = req.body.name
|
||||
# Optional - as long as course(s) are all free
|
||||
stripeToken = req.body.token
|
||||
stripeToken = req.body.stripe?.token
|
||||
|
||||
@getCourses courseID, (err, courses) =>
|
||||
query = if courseID? then {_id: courseID} else {}
|
||||
Course.find query, (err, courses) =>
|
||||
if err
|
||||
@logError(req.user, err)
|
||||
return @sendDatabaseError(res, err)
|
||||
@logError(user, "Find courses error: #{JSON.stringify(err)}")
|
||||
return done(err)
|
||||
|
||||
price = getCoursesPrice(courses, seats)
|
||||
if price > 0 and not stripeToken
|
||||
@logError(req.user, 'Course create API missing required Stripe token')
|
||||
return @sendBadInputError(res, 'Missing required Stripe token')
|
||||
PrepaidHandler.purchasePrepaidCourse req.user, courses, seats, new Date().getTime(), stripeToken, (err, prepaid) =>
|
||||
if err
|
||||
@logError(req.user, err)
|
||||
return @sendBadInputError(res, err) if err is 'Missing required Stripe token'
|
||||
return @sendDatabaseError(res, err)
|
||||
|
||||
# TODO: purchase prepaid for courses, price, and seats
|
||||
Prepaid.generateNewCode (code) =>
|
||||
return @sendDatabaseError(res, 'Database error.') unless code
|
||||
prepaid = new Prepaid
|
||||
creator: req.user.get('_id')
|
||||
type: 'course'
|
||||
code: code
|
||||
properties:
|
||||
courseIDs: (course.get('_id') for course in courses)
|
||||
prepaid.set('maxRedeemers', seats) if seats
|
||||
prepaid.save (err) =>
|
||||
courseInstances = []
|
||||
makeCreateInstanceFn = (course, name, prepaid) =>
|
||||
(done) =>
|
||||
@createInstance req, course, name, prepaid, (err, newInstance)=>
|
||||
courseInstances.push newInstance unless err
|
||||
done(err)
|
||||
tasks = (makeCreateInstanceFn(course, name, prepaid) for course in courses)
|
||||
async.parallel tasks, (err, results) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
|
||||
courseInstances = []
|
||||
makeCreateInstanceFn = (course, name, prepaid) =>
|
||||
(done) =>
|
||||
@createInstance req, course, name, prepaid, (err, newInstance)=>
|
||||
courseInstances.push newInstance unless err
|
||||
done(err)
|
||||
# tasks = []
|
||||
# tasks.push(makeCreateInstanceFn(course, name, prepaid)) for course in courses
|
||||
tasks = (makeCreateInstanceFn(course, name, prepaid) for course in courses)
|
||||
async.parallel tasks, (err, results) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
@sendCreated(res, courseInstances)
|
||||
@sendCreated(res, courseInstances)
|
||||
|
||||
createInstance: (req, course, name, prepaid, done) =>
|
||||
courseInstance = new CourseInstance
|
||||
|
@ -93,14 +81,6 @@ CourseInstanceHandler = class CourseInstanceHandler extends Handler
|
|||
courseInstance.save (err, newInstance) =>
|
||||
done(err, newInstance)
|
||||
|
||||
getCourses: (courseID, done) =>
|
||||
if courseID
|
||||
Course.findById courseID, (err, document) =>
|
||||
done(err, [document])
|
||||
else
|
||||
Course.find {}, (err, documents) =>
|
||||
done(err, documents)
|
||||
|
||||
getLevelSessionsAPI: (req, res, courseInstanceID) ->
|
||||
CourseInstance.findById courseInstanceID, (err, courseInstance) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
|
|
|
@ -7,6 +7,7 @@ module.exports =
|
|||
log.error "Stripe Utils Error: #{user.get('slug')} (#{user._id}): '#{msg}'"
|
||||
|
||||
createCharge: (user, amount, metadata, done) ->
|
||||
# TODO: create Stripe customer if necessary
|
||||
options =
|
||||
amount: amount
|
||||
currency: 'usd'
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
Course = require '../courses/Course'
|
||||
Handler = require '../commons/Handler'
|
||||
hipchat = require '../hipchat'
|
||||
Prepaid = require './Prepaid'
|
||||
StripeUtils = require '../lib/stripe_utils'
|
||||
{getPrepaidCodeAmount} = require '../../app/core/utils'
|
||||
hipchat = require '../hipchat'
|
||||
utils = require '../../app/core/utils'
|
||||
|
||||
# TODO: Should this happen on a save() call instead of a prepaid/-/create post?
|
||||
# TODO: Probably a better way to create a unique 8 charactor string property using db voodoo
|
||||
|
@ -14,20 +15,20 @@ PrepaidHandler = class PrepaidHandler extends Handler
|
|||
|
||||
baseAmount: 999
|
||||
|
||||
logPurchaseError: (user, msg) ->
|
||||
console.warn "Prepaid Purchase Error: [#{user.get('slug')} (#{user._id})] '#{msg}'"
|
||||
logError: (user, msg) ->
|
||||
console.warn "Prepaid Error: [#{user.get('slug')} (#{user._id})] '#{msg}'"
|
||||
|
||||
hasAccess: (req) ->
|
||||
req.user?.isAdmin()
|
||||
|
||||
getByRelationship: (req, res, args...) ->
|
||||
relationship = args[1]
|
||||
return @getPrepaid(req, res, args[2]) if relationship is 'code'
|
||||
return @createPrepaid(req, res) if relationship is 'create'
|
||||
return @purchasePrepaid(req, res) if relationship is 'purchase'
|
||||
return @getPrepaidAPI(req, res, args[2]) if relationship is 'code'
|
||||
return @createPrepaidAPI(req, res) if relationship is 'create'
|
||||
return @purchasePrepaidAPI(req, res) if relationship is 'purchase'
|
||||
super arguments...
|
||||
|
||||
getPrepaid: (req, res, code) ->
|
||||
getPrepaidAPI: (req, res, code) ->
|
||||
return @sendForbiddenError(res) unless req.user?
|
||||
return @sendNotFoundError(res, "You must specify a code") unless code
|
||||
|
||||
|
@ -40,85 +41,168 @@ PrepaidHandler = class PrepaidHandler extends Handler
|
|||
|
||||
@sendSuccess(res, prepaid.toObject())
|
||||
|
||||
createPrepaid: (req, res) ->
|
||||
createPrepaidAPI: (req, res) ->
|
||||
return @sendForbiddenError(res) unless @hasAccess(req)
|
||||
return @sendForbiddenError(res) unless req.body.type in ['subscription','terminal_subscription']
|
||||
return @sendForbiddenError(res) unless req.body.type in ['course', 'subscription','terminal_subscription']
|
||||
return @sendForbiddenError(res) unless req.body.maxRedeemers > 0
|
||||
|
||||
properties = {}
|
||||
type = req.body.type
|
||||
maxRedeemers = req.body.maxRedeemers
|
||||
|
||||
if req.body.type is 'course'
|
||||
return @sendDatabaseError(res, "TODO: need to add courseIDs")
|
||||
else if req.body.type is 'subscription'
|
||||
properties.couponID = 'free'
|
||||
else if req.body.type is 'terminal_subscription'
|
||||
properties.months = req.body.months
|
||||
|
||||
@createPrepaid req.user, req.body.type, req.body.maxRedeemers, properties, (err, prepaid) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
@sendSuccess(res, prepaid.toObject())
|
||||
|
||||
createPrepaid: (user, type, maxRedeemers, properties, done) ->
|
||||
Prepaid.generateNewCode (code) =>
|
||||
return @sendDatabaseError(res, 'Database error.') unless code
|
||||
# TODO: change the creator to use ObjectID like with the terminal_subscription
|
||||
return done('Database error.') unless code
|
||||
options =
|
||||
creator: req.user.id
|
||||
type: req.body.type
|
||||
creator: user._id
|
||||
type: type
|
||||
code: code
|
||||
maxRedeemers: req.body.maxRedeemers
|
||||
properties: {}
|
||||
maxRedeemers: maxRedeemers
|
||||
properties: properties
|
||||
redeemers: []
|
||||
|
||||
if req.body.type is 'subscription'
|
||||
options.properties.couponID = 'free'
|
||||
|
||||
if req.body.type is 'terminal_subscription'
|
||||
options.properties.months = req.body.months
|
||||
options.creator = req.user._id
|
||||
|
||||
prepaid = new Prepaid options
|
||||
prepaid.save (err) =>
|
||||
return done(err) if err
|
||||
done(err, prepaid)
|
||||
|
||||
purchasePrepaidAPI: (req, res) ->
|
||||
return @sendUnauthorizedError(res) if not req.user? or req.user?.isAnonymous()
|
||||
return @sendForbiddenError(res) unless req.body.type in ['course', 'terminal_subscription']
|
||||
|
||||
if req.body.type is 'terminal_subscription'
|
||||
description = req.body.description
|
||||
maxRedeemers = parseInt(req.body.maxRedeemers)
|
||||
months = parseInt(req.body.months)
|
||||
timestamp = req.body.stripe?.timestamp
|
||||
token = req.body.stripe?.token
|
||||
|
||||
return @sendBadInputError(res) unless isNaN(maxRedeemers) is false and maxRedeemers > 0
|
||||
return @sendBadInputError(res) unless isNaN(months) is false and months > 0
|
||||
return @sendError(res, 403, "Users or Months must be greater than 3") if maxRedeemers < 3 and months < 3
|
||||
|
||||
@purchasePrepaidTerminalSubscription req.user, description, maxRedeemers, months, timestamp, token, (err, prepaid) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
@sendSuccess(res, prepaid.toObject())
|
||||
|
||||
purchasePrepaid: (req, res) ->
|
||||
return @sendForbiddenError(res) unless req.user?
|
||||
return @sendForbiddenError(res) unless req.body.type is 'terminal_subscription'
|
||||
else if req.body.type is 'course'
|
||||
courseID = req.body.courseID
|
||||
|
||||
maxRedeemers = parseInt(req.body.maxRedeemers)
|
||||
months = parseInt(req.body.months)
|
||||
maxRedeemers = parseInt(req.body.maxRedeemers)
|
||||
timestamp = req.body.stripe?.timestamp
|
||||
token = req.body.stripe?.token
|
||||
|
||||
return @sendForbiddenError(res) unless isNaN(maxRedeemers) is false and maxRedeemers > 0
|
||||
return @sendForbiddenError(res) unless isNaN(months) is false and months > 0
|
||||
return @sendError(res, 403, "Users or Months must be greater than 3") if maxRedeemers < 3 and months < 3
|
||||
return @sendBadInputError(res) unless isNaN(maxRedeemers) is false and maxRedeemers > 0
|
||||
|
||||
StripeUtils.getCustomer req.user, req.body.stripe?.token, (err, customer) =>
|
||||
query = if courseID? then {_id: courseID} else {}
|
||||
Course.find query, (err, courses) =>
|
||||
if err
|
||||
@logError(user, "Find courses error: #{JSON.stringify(err)}")
|
||||
return done(err)
|
||||
|
||||
@purchasePrepaidCourse req.user, courses, maxRedeemers, timestamp, token, (err, prepaid) =>
|
||||
# TODO: this badinput detection is fragile, in course instance handler as well
|
||||
return @sendBadInputError(res, err) if err is 'Missing required Stripe token'
|
||||
return @sendDatabaseError(res, err) if err
|
||||
@sendSuccess(res, prepaid.toObject())
|
||||
else
|
||||
@sendForbiddenError(res)
|
||||
|
||||
purchasePrepaidCourse: (user, courses, maxRedeemers, timestamp, token, done) ->
|
||||
type = 'course'
|
||||
|
||||
courseIDs = (c.get('_id') for c in courses)
|
||||
coursePrices = (c.get('pricePerSeat') for c in courses)
|
||||
amount = utils.getCourseBundlePrice(coursePrices, maxRedeemers)
|
||||
if amount > 0 and not token
|
||||
@logError(user, "Purchase prepaid courses missing required Stripe token #{amount}")
|
||||
return done('Missing required Stripe token')
|
||||
|
||||
if amount is 0
|
||||
@createPrepaid(user, type, maxRedeemers, courseIDs: courseIDs, done)
|
||||
|
||||
else
|
||||
StripeUtils.getCustomer user, token, (err, customer) =>
|
||||
if err
|
||||
@logError(user, "Stripe getCustomer error: #{JSON.stringify(err)}")
|
||||
return done(err)
|
||||
|
||||
metadata =
|
||||
type: type
|
||||
userID: user.id
|
||||
timestamp: parseInt(timestamp)
|
||||
description: if courses.length is 1 then courses[0].get('name') else 'All Courses'
|
||||
maxRedeemers: maxRedeemers
|
||||
productID: "prepaid #{type}"
|
||||
courseIDs: courseIDs
|
||||
|
||||
StripeUtils.createCharge user, amount, metadata, (err, charge) =>
|
||||
if err
|
||||
@logError(user, "createCharge error: #{JSON.stringify(err)}")
|
||||
return done(err)
|
||||
|
||||
StripeUtils.createPayment user, charge, (err, payment) =>
|
||||
if err
|
||||
@logError(user, "createPayment error: #{JSON.stringify(err)}")
|
||||
return done(err)
|
||||
msg = "Prepaid code purchased: #{type} seats=#{maxRedeemers} courseIDs=#{courseIDs} #{user.get('email')}"
|
||||
hipchat.sendHipChatMessage msg, ['tower']
|
||||
@createPrepaid(user, type, maxRedeemers, courseIDs: courseIDs, done)
|
||||
|
||||
purchasePrepaidTerminalSubscription: (user, description, maxRedeemers, months, timestamp, token, done) ->
|
||||
type = 'terminal_subscription'
|
||||
|
||||
StripeUtils.getCustomer user, token, (err, customer) =>
|
||||
if err
|
||||
@logPurchaseError(req.user, "getCustomer error: #{JSON.stringify(err)}")
|
||||
return @sendDatabaseError(res, err)
|
||||
@logError(user, "getCustomer error: #{JSON.stringify(err)}")
|
||||
return done(err)
|
||||
|
||||
metadata =
|
||||
type: req.body.type
|
||||
userID: req.user._id + ''
|
||||
timestamp: parseInt(req.body.stripe?.timestamp)
|
||||
description: req.body.description
|
||||
type: type
|
||||
userID: user.id
|
||||
timestamp: parseInt(timestamp)
|
||||
description: description
|
||||
maxRedeemers: maxRedeemers
|
||||
months: months
|
||||
productID: 'prepaid ' + req.body.type
|
||||
productID: "prepaid #{type}"
|
||||
|
||||
amount = getPrepaidCodeAmount(@baseAmount, maxRedeemers, months)
|
||||
amount = utils.getPrepaidCodeAmount(@baseAmount, maxRedeemers, months)
|
||||
|
||||
StripeUtils.createCharge req.user, amount, metadata, (err, charge) =>
|
||||
StripeUtils.createCharge user, amount, metadata, (err, charge) =>
|
||||
if err
|
||||
@logPurchaseError(req.user, "createCharge error: #{JSON.stringify(err)}")
|
||||
return @sendDatabaseError(res, err)
|
||||
@logError(user, "createCharge error: #{JSON.stringify(err)}")
|
||||
return done(err)
|
||||
|
||||
StripeUtils.createPayment req.user, charge, (err, payment) =>
|
||||
StripeUtils.createPayment user, charge, (err, payment) =>
|
||||
if err
|
||||
@logPurchaseError(req.user, "createPayment error: #{JSON.stringify(err)}")
|
||||
return @sendDatabaseError(res, err)
|
||||
@logError(user, "createPayment error: #{JSON.stringify(err)}")
|
||||
return done(err)
|
||||
|
||||
Prepaid.generateNewCode (code) =>
|
||||
return @sendDatabaseError(res, 'Database error.') unless code
|
||||
return done('Database error.') unless code
|
||||
prepaid = new Prepaid
|
||||
creator: req.user._id
|
||||
type: req.body.type
|
||||
creator: user._id
|
||||
type: type
|
||||
code: code
|
||||
maxRedeemers: req.body.maxRedeemers
|
||||
maxRedeemers: maxRedeemers
|
||||
redeemers: []
|
||||
properties:
|
||||
months: req.body.months
|
||||
months: months
|
||||
prepaid.save (err) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
msg = "Prepaid code (#{req.body.maxRedeemers} users / #{req.body.months} months) purchased by #{req.user.get('email')}"
|
||||
return done(err) if err
|
||||
msg = "Prepaid code purchased: #{type} users=#{maxRedeemers} months=#{months} #{user.get('email')}"
|
||||
hipchat.sendHipChatMessage msg, ['tower']
|
||||
@sendSuccess(res, prepaid.toObject())
|
||||
return done(null, prepaid)
|
||||
|
||||
module.exports = new PrepaidHandler()
|
||||
|
|
|
@ -120,6 +120,23 @@ wrapUpGetUser = (email, user, done) ->
|
|||
GLOBAL.getURL = (path) ->
|
||||
return 'http://localhost:3001' + path
|
||||
|
||||
nameCount = 0
|
||||
GLOBAL.createName = (name) ->
|
||||
name + nameCount++
|
||||
|
||||
GLOBAL.createCourse = (pricePerSeat, done) ->
|
||||
name = createName 'course '
|
||||
course = new Course
|
||||
name: name
|
||||
campaignID: ObjectId("55b29efd1cd6abe8ce07db0d")
|
||||
concepts: ['basic_syntax', 'arguments', 'while_loops', 'strings', 'variables']
|
||||
description: "Learn basic syntax, while loops, and the CodeCombat environment."
|
||||
pricePerSeat: pricePerSeat
|
||||
screenshot: "/images/pages/courses/101_info.png"
|
||||
course.save (err, course) =>
|
||||
return done(err) if err
|
||||
done(err, course)
|
||||
|
||||
GLOBAL.createPrepaid = (type, maxRedeemers, months, done) ->
|
||||
options = uri: GLOBAL.getURL('/db/prepaid/-/create')
|
||||
options.json =
|
||||
|
@ -133,14 +150,18 @@ GLOBAL.fetchPrepaid = (ppc, done) ->
|
|||
options = uri: GLOBAL.getURL('/db/prepaid/-/code/'+ppc)
|
||||
request.get options, done
|
||||
|
||||
GLOBAL.purchasePrepaid = (type, maxRedeemers, months, done) ->
|
||||
GLOBAL.purchasePrepaid = (type, properties, maxRedeemers, token, done) ->
|
||||
options = uri: GLOBAL.getURL('/db/prepaid/-/purchase')
|
||||
options.json =
|
||||
type: type
|
||||
maxRedeemers: maxRedeemers
|
||||
months: months
|
||||
stripe:
|
||||
timestamp: new Date().getTime()
|
||||
options.json.stripe.token = token if token?
|
||||
if type is 'terminal_subscription'
|
||||
options.json.months = properties.months
|
||||
else if type is 'course'
|
||||
options.json.courseID = properties.courseID if properties?.courseID
|
||||
request.post options, done
|
||||
|
||||
GLOBAL.subscribeWithPrepaid = (ppc, done) =>
|
||||
|
|
|
@ -9,29 +9,14 @@ describe 'CourseInstance', ->
|
|||
courseInstanceURL = getURL('/db/course_instance/-/create')
|
||||
userURL = getURL('/db/user')
|
||||
|
||||
nameCount = 0
|
||||
createName = (name) -> name + nameCount++
|
||||
|
||||
createCourse = (pricePerSeat, done) ->
|
||||
name = createName 'course '
|
||||
course = new Course
|
||||
name: name
|
||||
campaignID: ObjectId("55b29efd1cd6abe8ce07db0d")
|
||||
concepts: ['basic_syntax', 'arguments', 'while_loops', 'strings', 'variables']
|
||||
description: "Learn basic syntax, while loops, and the CodeCombat environment."
|
||||
pricePerSeat: pricePerSeat
|
||||
screenshot: "/images/pages/courses/101_info.png"
|
||||
course.save (err, course) ->
|
||||
return done(err) if err
|
||||
done(err, course)
|
||||
|
||||
createCourseInstances = (user, courseID, seats, token, done) ->
|
||||
name = createName 'course instance '
|
||||
requestBody =
|
||||
courseID: courseID
|
||||
name: name
|
||||
seats: seats
|
||||
token: token
|
||||
stripe:
|
||||
token: token
|
||||
request.post {uri: courseInstanceURL, json: requestBody }, (err, res) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toBe(201)
|
||||
|
@ -64,7 +49,7 @@ describe 'CourseInstance', ->
|
|||
return done(err) if err
|
||||
done(err, courseInstances)
|
||||
|
||||
it 'Clear database users and clans', (done) ->
|
||||
it 'Clear database', (done) ->
|
||||
clearModels [User, Course, CourseInstance, Prepaid], (err) ->
|
||||
throw err if err
|
||||
done()
|
||||
|
@ -124,7 +109,12 @@ describe 'CourseInstance', ->
|
|||
expect(err).toBeNull()
|
||||
return done(err) if err
|
||||
expect(courseInstances.length).toEqual(1)
|
||||
done()
|
||||
Prepaid.findById courseInstances[0].get('prepaidID'), (err, prepaid) ->
|
||||
expect(err).toBeNull()
|
||||
return done(err) if err
|
||||
expect(prepaid.get('maxRedeemers')).toEqual(1)
|
||||
expect(prepaid.get('properties')?.courseIDs).toEqual([course.get('_id')])
|
||||
done()
|
||||
|
||||
it 'Create for paid course 50 seats', (done) ->
|
||||
stripe.tokens.create {
|
||||
|
@ -138,7 +128,12 @@ describe 'CourseInstance', ->
|
|||
expect(err).toBeNull()
|
||||
return done(err) if err
|
||||
expect(courseInstances.length).toEqual(1)
|
||||
done()
|
||||
Prepaid.findById courseInstances[0].get('prepaidID'), (err, prepaid) ->
|
||||
expect(err).toBeNull()
|
||||
return done(err) if err
|
||||
expect(prepaid.get('maxRedeemers')).toEqual(50)
|
||||
expect(prepaid.get('properties')?.courseIDs).toEqual([course.get('_id')])
|
||||
done()
|
||||
|
||||
it 'Create for paid course no token', (done) ->
|
||||
loginNewUser (user1) ->
|
||||
|
@ -192,4 +187,12 @@ describe 'CourseInstance', ->
|
|||
expect(err).toBeNull()
|
||||
return done(err) if err
|
||||
expect(courseInstances.length).toEqual(courses.length)
|
||||
done()
|
||||
Prepaid.find creator: user1.get('_id'), (err, prepaids) ->
|
||||
expect(err).toBeNull()
|
||||
return done(err) if err
|
||||
expect(prepaids.length).toEqual(1)
|
||||
return done('no prepaids found') unless prepaids?.length > 0
|
||||
prepaid = prepaids[0]
|
||||
expect(prepaid.get('maxRedeemers')).toEqual(50)
|
||||
expect(prepaid.get('properties')?.courseIDs?.length).toEqual(courses.length)
|
||||
done()
|
||||
|
|
|
@ -13,7 +13,15 @@ describe '/db/prepaid', ->
|
|||
stripe = require('stripe')(config.stripe.secretKey)
|
||||
joeCode = null
|
||||
|
||||
verifyPrepaid = (user, prepaid, done) ->
|
||||
verifyCoursePrepaid = (user, prepaid, done) ->
|
||||
expect(prepaid.creator).toEqual(user.id)
|
||||
expect(prepaid.type).toEqual('course')
|
||||
expect(prepaid.maxRedeemers).toBeGreaterThan(0)
|
||||
expect(prepaid.code).toMatch(/^\w{8}$/)
|
||||
expect(prepaid.properties?.courseIDs?.length).toBeGreaterThan(0)
|
||||
done()
|
||||
|
||||
verifySubscriptionPrepaid = (user, prepaid, done) ->
|
||||
expect(prepaid.creator).toEqual(user.id)
|
||||
expect(prepaid.type).toEqual('subscription')
|
||||
expect(prepaid.maxRedeemers).toBeGreaterThan(0)
|
||||
|
@ -21,8 +29,8 @@ describe '/db/prepaid', ->
|
|||
expect(prepaid.properties?.couponID).toEqual('free')
|
||||
done()
|
||||
|
||||
it 'Clear database users and prepaids', (done) ->
|
||||
clearModels [User, Prepaid, Payment], (err) ->
|
||||
it 'Clear database', (done) ->
|
||||
clearModels [Course, CourseInstance, Payment, Prepaid, User], (err) ->
|
||||
throw err if err
|
||||
done()
|
||||
|
||||
|
@ -49,7 +57,7 @@ describe '/db/prepaid', ->
|
|||
createPrepaid 'subscription', 1, 0, (err, res, body) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toBe(200)
|
||||
verifyPrepaid user1, body, done
|
||||
verifySubscriptionPrepaid user1, body, done
|
||||
|
||||
it 'Admin creates prepaid code with type terminal_subscription', (done) ->
|
||||
loginNewUser (user1) ->
|
||||
|
@ -126,237 +134,333 @@ describe '/db/prepaid', ->
|
|||
for p in prepaids
|
||||
if p._id is prepaid._id
|
||||
found = true
|
||||
verifyPrepaid user1, p, done
|
||||
verifySubscriptionPrepaid user1, p, done
|
||||
break
|
||||
expect(found).toEqual(true)
|
||||
done() unless found
|
||||
|
||||
# *** Purchase Prepaid Codes *** #
|
||||
it 'Anonymous submits a prepaid purchase', (done) ->
|
||||
logoutUser () ->
|
||||
purchasePrepaid 'terminal_subscription', 3, 3, (err, res, prepaid) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toBe(401)
|
||||
done()
|
||||
|
||||
it 'Should error if type isnt terminal_subscription', (done) ->
|
||||
loginNewUser (user1) ->
|
||||
purchasePrepaid 'subscription', 3, 3, (err, res, prepaid) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toBe(403)
|
||||
done()
|
||||
|
||||
it 'Should error if maxRedeemers is invalid', (done) ->
|
||||
loginNewUser (user1) ->
|
||||
purchasePrepaid 'terminal_subscription', -1, 3, (err, res, prepaid) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toBe(403)
|
||||
done()
|
||||
purchasePrepaid 'terminal_subscription', 'foo', 3, (err, res, prepaid) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toBe(403)
|
||||
done()
|
||||
|
||||
it 'Should error if months is invalid', (done) ->
|
||||
loginNewUser (user1) ->
|
||||
purchasePrepaid 'terminal_subscription', 3, -1, (err, res, prepaid) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toBe(403)
|
||||
done()
|
||||
purchasePrepaid 'terminal_subscription', 3, 'foo', (err, res, prepaid) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toBe(403)
|
||||
done()
|
||||
|
||||
it 'Should error if maxRedeemers and months are less than 3', (done) ->
|
||||
loginNewUser (user1) ->
|
||||
purchasePrepaid 'terminal_subscription', 1, 1, (err, res, prepaid) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toBe(403)
|
||||
done()
|
||||
|
||||
it 'User submits valid prepaid code purchase', (done) ->
|
||||
stripe.tokens.create {
|
||||
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
||||
}, (err, token) ->
|
||||
stripeTokenID = token.id
|
||||
loginJoe (joe) ->
|
||||
joeData = joe.toObject()
|
||||
joeData.stripe = {
|
||||
token: stripeTokenID
|
||||
planID: 'basic'
|
||||
}
|
||||
request.put {uri: getURL('/db/user'), json: joeData, headers: headers }, (err, res, body) ->
|
||||
joeData = body
|
||||
expect(res.statusCode).toBe(200)
|
||||
expect(joeData.stripe.customerID).toBeDefined()
|
||||
expect(firstSubscriptionID = joeData.stripe.subscriptionID).toBeDefined()
|
||||
expect(joeData.stripe.planID).toBe('basic')
|
||||
expect(joeData.stripe.token).toBeUndefined()
|
||||
purchasePrepaid 'terminal_subscription', 3, 3, (err, res, prepaid) ->
|
||||
describe 'Purchase course', ->
|
||||
it 'Standard user purchases a prepaid for one course, 0 seats', (done) ->
|
||||
stripe.tokens.create {
|
||||
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
||||
}, (err, token) ->
|
||||
loginNewUser (user1) ->
|
||||
createCourse 700, (err, course) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toBe(200)
|
||||
expect(prepaid.type).toEqual('terminal_subscription')
|
||||
expect(prepaid.code).toBeDefined()
|
||||
# Saving this code for later tests
|
||||
# TODO: don't make tests dependent on each other
|
||||
joeCode = prepaid.code
|
||||
expect(prepaid.creator).toBeDefined()
|
||||
expect(prepaid.maxRedeemers).toEqual(3)
|
||||
expect(prepaid.properties).toBeDefined()
|
||||
expect(prepaid.properties.months).toEqual(3)
|
||||
done()
|
||||
|
||||
it 'Should have logged a Payment with the correct amount', (done) ->
|
||||
loginJoe (joe) ->
|
||||
query =
|
||||
purchaser: joe._id
|
||||
Payment.find query, (err, payments) ->
|
||||
expect(err).toBeNull()
|
||||
expect(payments).not.toBeNull()
|
||||
expect(payments.length).toEqual(1)
|
||||
expect(payments[0].get('amount')).toEqual(8991)
|
||||
done()
|
||||
|
||||
|
||||
it 'Anonymous cant redeem a prepaid code', (done) ->
|
||||
logoutUser () ->
|
||||
subscribeWithPrepaid joeCode, (err, res) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res?.statusCode).toEqual(401)
|
||||
done()
|
||||
|
||||
|
||||
it 'User cant redeem a nonexistant prepaid code', (done) ->
|
||||
loginJoe (joe) ->
|
||||
subscribeWithPrepaid 'abc123', (err, res) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toEqual(403)
|
||||
done()
|
||||
|
||||
it 'User cant redeem empty code', (done) ->
|
||||
loginJoe (joe) ->
|
||||
subscribeWithPrepaid '', (err, res) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toEqual(422)
|
||||
done()
|
||||
|
||||
it 'Anonymous cant fetch a prepaid code', (done) ->
|
||||
expect(joeCode).not.toBeNull()
|
||||
logoutUser () ->
|
||||
fetchPrepaid joeCode, (err, res) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toEqual(403)
|
||||
done()
|
||||
|
||||
it 'User can fetch a prepaid code', (done) ->
|
||||
expect(joeCode).not.toBeNull()
|
||||
loginJoe (joe) ->
|
||||
fetchPrepaid joeCode, (err, res, body) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toEqual(200)
|
||||
|
||||
expect(body).toBeDefined()
|
||||
return done() unless body
|
||||
|
||||
prepaid = JSON.parse(body)
|
||||
expect(prepaid.code).toEqual(joeCode)
|
||||
expect(prepaid.maxRedeemers).toEqual(3)
|
||||
expect(prepaid.properties?.months).toEqual(3)
|
||||
done()
|
||||
|
||||
# TODO: Move redeem subscription prepaid code tests to subscription tests file
|
||||
|
||||
it 'Creator can redeeem a prepaid code', (done) ->
|
||||
loginJoe (joe) ->
|
||||
expect(joeCode).not.toBeNull()
|
||||
expect(joeData.stripe?.customerID).toBeDefined()
|
||||
expect(joeData.stripe?.subscriptionID).toBeDefined()
|
||||
return done() unless joeData.stripe?.customerID
|
||||
|
||||
# joe has a stripe subscription, so test if the months are added to the end of it.
|
||||
stripe.customers.retrieve joeData.stripe.customerID, (err, customer) =>
|
||||
expect(err).toBeNull()
|
||||
|
||||
findStripeSubscription customer.id, subscriptionID: joeData.stripe?.subscriptionID, (subscription) =>
|
||||
if subscription
|
||||
stripeSubscriptionPeriodEndDate = new moment(subscription.current_period_end * 1000)
|
||||
else
|
||||
expect(stripeSubscriptionPeriodEndDate).toBeDefined()
|
||||
return done()
|
||||
|
||||
subscribeWithPrepaid joeCode, (err, res, result) =>
|
||||
purchasePrepaid 'course', courseID: course.id, 0, token.id, (err, res, prepaid) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toBe(422)
|
||||
done()
|
||||
it 'Standard user purchases a prepaid for one course, 1 seat', (done) ->
|
||||
stripe.tokens.create {
|
||||
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
||||
}, (err, token) ->
|
||||
loginNewUser (user1) ->
|
||||
createCourse 700, (err, course) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toEqual(200)
|
||||
endDate = stripeSubscriptionPeriodEndDate.add(3, 'months').toISOString().substring(0, 10)
|
||||
expect(result?.stripe?.free).toEqual(endDate)
|
||||
expect(result?.purchased?.gems).toEqual(14000)
|
||||
findStripeSubscription customer.id, subscriptionID: joeData.stripe?.subscriptionID, (subscription) =>
|
||||
expect(subscription).toBeNull()
|
||||
purchasePrepaid 'course', courseID: course.id, 1, token.id, (err, res, prepaid) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toBe(200)
|
||||
verifyCoursePrepaid(user1, prepaid, done)
|
||||
it 'Standard user purchases a prepaid for one course, 3 seats', (done) ->
|
||||
stripe.tokens.create {
|
||||
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
||||
}, (err, token) ->
|
||||
loginNewUser (user1) ->
|
||||
createCourse 700, (err, course) ->
|
||||
expect(err).toBeNull()
|
||||
purchasePrepaid 'course', courseID: course.id, 3, token.id, (err, res, prepaid) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toBe(200)
|
||||
verifyCoursePrepaid(user1, prepaid, done)
|
||||
it 'Standard user purchases a prepaid for all courses, 10 seats', (done) ->
|
||||
clearModels [Course, CourseInstance, Payment, Prepaid, User], (err) ->
|
||||
throw err if err
|
||||
stripe.tokens.create {
|
||||
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
||||
}, (err, token) ->
|
||||
loginNewUser (user1) ->
|
||||
createCourse 700, (err, course) ->
|
||||
expect(err).toBeNull()
|
||||
createCourse 700, (err, course) ->
|
||||
expect(err).toBeNull()
|
||||
purchasePrepaid 'course', null, 10, token.id, (err, res, prepaid) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toBe(200)
|
||||
expect(prepaid.properties?.courseIDs?.length).toEqual(2)
|
||||
verifyCoursePrepaid(user1, prepaid, done)
|
||||
|
||||
it 'Standard user purchases a prepaid course for 3', (done) ->
|
||||
stripe.tokens.create {
|
||||
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
||||
}, (err, token) ->
|
||||
loginNewUser (user1) ->
|
||||
createCourse 700, (err, course) ->
|
||||
expect(err).toBeNull()
|
||||
purchasePrepaid 'course', courseID: course.id, 3, token.id, (err, res, prepaid) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toBe(200)
|
||||
done()
|
||||
|
||||
it 'User can redeem a prepaid code', (done) ->
|
||||
loginSam (sam) ->
|
||||
subscribeWithPrepaid joeCode, (err, res, result) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toEqual(200)
|
||||
endDate = new moment().add(3, 'months').toISOString().substring(0, 10)
|
||||
expect(result?.stripe?.free).toEqual(endDate)
|
||||
expect(result?.purchased?.gems).toEqual(10500)
|
||||
done()
|
||||
describe 'Purchase terminal_subscription', ->
|
||||
it 'Anonymous submits a prepaid purchase', (done) ->
|
||||
stripe.tokens.create {
|
||||
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
||||
}, (err, token) ->
|
||||
logoutUser () ->
|
||||
purchasePrepaid 'terminal_subscription', months: 3, 3, token.id, (err, res, prepaid) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toBe(401)
|
||||
done()
|
||||
|
||||
it 'Wont allow the same person to redeem twice', (done) ->
|
||||
loginSam (sam) ->
|
||||
subscribeWithPrepaid joeCode, (err, res, result) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toEqual(403)
|
||||
done()
|
||||
it 'Should error if type isnt terminal_subscription', (done) ->
|
||||
stripe.tokens.create {
|
||||
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
||||
}, (err, token) ->
|
||||
loginNewUser (user1) ->
|
||||
purchasePrepaid 'subscription', months: 3, 3, token.id, (err, res, prepaid) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toBe(403)
|
||||
done()
|
||||
|
||||
it 'Will return redeemed code as part of codes list', (done) ->
|
||||
loginSam (sam) ->
|
||||
request.get "#{getURL('/db/user')}/#{sam.id}/prepaid_codes", (err, res) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toEqual(200)
|
||||
codes = JSON.parse res.body
|
||||
expect(codes.length).toEqual(1)
|
||||
done()
|
||||
it 'Should error if maxRedeemers is -1', (done) ->
|
||||
stripe.tokens.create {
|
||||
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
||||
}, (err, token) ->
|
||||
loginNewUser (user1) ->
|
||||
purchasePrepaid 'terminal_subscription', months: 3, -1, token.id, (err, res, prepaid) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toBe(422)
|
||||
done()
|
||||
|
||||
it 'Third user can redeem a prepaid code', (done) ->
|
||||
loginNewUser (user) ->
|
||||
subscribeWithPrepaid joeCode, (err, res, result) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toEqual(200)
|
||||
endDate = new moment().add(3, 'months').toISOString().substring(0, 10)
|
||||
expect(result?.stripe?.free).toEqual(endDate)
|
||||
expect(result?.purchased?.gems).toEqual(10500)
|
||||
done()
|
||||
it 'Should error if maxRedeemers is foo', (done) ->
|
||||
stripe.tokens.create {
|
||||
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
||||
}, (err, token) ->
|
||||
loginNewUser (user1) ->
|
||||
purchasePrepaid 'terminal_subscription', months: 3, 'foo', token.id, (err, res, prepaid) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toBe(422)
|
||||
done()
|
||||
|
||||
it 'Fourth user cannot redeem code', (done) ->
|
||||
loginNewUser (user) ->
|
||||
subscribeWithPrepaid joeCode, (err, res, result) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toEqual(403)
|
||||
done()
|
||||
it 'Should error if months is -1', (done) ->
|
||||
stripe.tokens.create {
|
||||
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
||||
}, (err, token) ->
|
||||
loginNewUser (user1) ->
|
||||
purchasePrepaid 'terminal_subscription', months: -1, 3, token.id, (err, res, prepaid) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toBe(422)
|
||||
done()
|
||||
|
||||
it 'Should error if months is foo', (done) ->
|
||||
stripe.tokens.create {
|
||||
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
||||
}, (err, token) ->
|
||||
loginNewUser (user1) ->
|
||||
purchasePrepaid 'terminal_subscription', months: 'foo', 3, token.id, (err, res, prepaid) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toBe(422)
|
||||
done()
|
||||
|
||||
it 'Can fetch a list of purchased and redeemed prepaid codes', (done) ->
|
||||
loginJoe (joe) ->
|
||||
purchasePrepaid 'terminal_subscription', 3, 1, (err, res, prepaid) ->
|
||||
request.get "#{getURL('/db/user')}/#{joe.id}/prepaid_codes", (err, res) ->
|
||||
it 'Should error if maxRedeemers and months are less than 3', (done) ->
|
||||
stripe.tokens.create {
|
||||
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
||||
}, (err, token) ->
|
||||
loginNewUser (user1) ->
|
||||
purchasePrepaid 'terminal_subscription', months: 1, 1, token.id, (err, res, prepaid) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toBe(403)
|
||||
done()
|
||||
|
||||
it 'User submits valid prepaid code purchase', (done) ->
|
||||
stripe.tokens.create {
|
||||
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
||||
}, (err, token) ->
|
||||
stripeTokenID = token.id
|
||||
loginJoe (joe) ->
|
||||
joeData = joe.toObject()
|
||||
joeData.stripe = {
|
||||
token: stripeTokenID
|
||||
planID: 'basic'
|
||||
}
|
||||
request.put {uri: getURL('/db/user'), json: joeData, headers: headers }, (err, res, body) ->
|
||||
joeData = body
|
||||
expect(res.statusCode).toBe(200)
|
||||
expect(joeData.stripe.customerID).toBeDefined()
|
||||
expect(firstSubscriptionID = joeData.stripe.subscriptionID).toBeDefined()
|
||||
expect(joeData.stripe.planID).toBe('basic')
|
||||
expect(joeData.stripe.token).toBeUndefined()
|
||||
# TODO: is this test still valid after new token?
|
||||
stripe.tokens.create {
|
||||
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
||||
}, (err, token) ->
|
||||
purchasePrepaid 'terminal_subscription', months: 3, 3, token.id, (err, res, prepaid) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toBe(200)
|
||||
expect(prepaid.type).toEqual('terminal_subscription')
|
||||
expect(prepaid.code).toBeDefined()
|
||||
# Saving this code for later tests
|
||||
# TODO: don't make tests dependent on each other
|
||||
joeCode = prepaid.code
|
||||
expect(prepaid.creator).toBeDefined()
|
||||
expect(prepaid.maxRedeemers).toEqual(3)
|
||||
expect(prepaid.properties).toBeDefined()
|
||||
expect(prepaid.properties.months).toEqual(3)
|
||||
done()
|
||||
|
||||
it 'Should have logged a Payment with the correct amount', (done) ->
|
||||
loginJoe (joe) ->
|
||||
query =
|
||||
purchaser: joe._id
|
||||
Payment.find query, (err, payments) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toEqual(200);
|
||||
codes = JSON.parse res.body
|
||||
expect(codes.length).toEqual(2)
|
||||
expect(codes[0].maxRedeemers).toEqual(3)
|
||||
expect(codes[0].properties).toBeDefined()
|
||||
expect(codes[0].properties.months).toEqual(3)
|
||||
expect(payments).not.toBeNull()
|
||||
expect(payments.length).toEqual(1)
|
||||
expect(payments[0].get('amount')).toEqual(8991)
|
||||
done()
|
||||
|
||||
it 'Test for injection', (done) ->
|
||||
loginNewUser (user) ->
|
||||
code = { $exists: true }
|
||||
subscribeWithPrepaid code, (err, res, result) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).not.toEqual(200)
|
||||
done()
|
||||
# TODO: add a bunch of parallel tests trying to redeem a code with a high maxRedeemers (50?) to see what happens
|
||||
|
||||
it 'Anonymous cant redeem a prepaid code', (done) ->
|
||||
logoutUser () ->
|
||||
subscribeWithPrepaid joeCode, (err, res) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res?.statusCode).toEqual(401)
|
||||
done()
|
||||
|
||||
it 'User cant redeem a nonexistant prepaid code', (done) ->
|
||||
loginJoe (joe) ->
|
||||
subscribeWithPrepaid 'abc123', (err, res) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toEqual(403)
|
||||
done()
|
||||
|
||||
it 'User cant redeem empty code', (done) ->
|
||||
loginJoe (joe) ->
|
||||
subscribeWithPrepaid '', (err, res) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toEqual(422)
|
||||
done()
|
||||
|
||||
it 'Anonymous cant fetch a prepaid code', (done) ->
|
||||
expect(joeCode).not.toBeNull()
|
||||
logoutUser () ->
|
||||
fetchPrepaid joeCode, (err, res) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toEqual(403)
|
||||
done()
|
||||
|
||||
it 'User can fetch a prepaid code', (done) ->
|
||||
expect(joeCode).not.toBeNull()
|
||||
loginJoe (joe) ->
|
||||
fetchPrepaid joeCode, (err, res, body) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toEqual(200)
|
||||
|
||||
expect(body).toBeDefined()
|
||||
return done() unless body
|
||||
|
||||
prepaid = JSON.parse(body)
|
||||
expect(prepaid.code).toEqual(joeCode)
|
||||
expect(prepaid.maxRedeemers).toEqual(3)
|
||||
expect(prepaid.properties?.months).toEqual(3)
|
||||
done()
|
||||
|
||||
# TODO: Move redeem subscription prepaid code tests to subscription tests file
|
||||
describe 'Subscription redeem tests', ->
|
||||
it 'Creator can redeeem a prepaid code', (done) ->
|
||||
loginJoe (joe) ->
|
||||
expect(joeCode).not.toBeNull()
|
||||
expect(joeData.stripe?.customerID).toBeDefined()
|
||||
expect(joeData.stripe?.subscriptionID).toBeDefined()
|
||||
return done() unless joeData.stripe?.customerID
|
||||
|
||||
# joe has a stripe subscription, so test if the months are added to the end of it.
|
||||
stripe.customers.retrieve joeData.stripe.customerID, (err, customer) =>
|
||||
expect(err).toBeNull()
|
||||
|
||||
findStripeSubscription customer.id, subscriptionID: joeData.stripe?.subscriptionID, (subscription) =>
|
||||
if subscription
|
||||
stripeSubscriptionPeriodEndDate = new moment(subscription.current_period_end * 1000)
|
||||
else
|
||||
expect(stripeSubscriptionPeriodEndDate).toBeDefined()
|
||||
return done()
|
||||
|
||||
subscribeWithPrepaid joeCode, (err, res, result) =>
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toEqual(200)
|
||||
endDate = stripeSubscriptionPeriodEndDate.add(3, 'months').toISOString().substring(0, 10)
|
||||
expect(result?.stripe?.free).toEqual(endDate)
|
||||
expect(result?.purchased?.gems).toEqual(14000)
|
||||
findStripeSubscription customer.id, subscriptionID: joeData.stripe?.subscriptionID, (subscription) =>
|
||||
expect(subscription).toBeNull()
|
||||
done()
|
||||
|
||||
it 'User can redeem a prepaid code', (done) ->
|
||||
loginSam (sam) ->
|
||||
subscribeWithPrepaid joeCode, (err, res, result) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toEqual(200)
|
||||
endDate = new moment().add(3, 'months').toISOString().substring(0, 10)
|
||||
expect(result?.stripe?.free).toEqual(endDate)
|
||||
expect(result?.purchased?.gems).toEqual(10500)
|
||||
done()
|
||||
|
||||
it 'Wont allow the same person to redeem twice', (done) ->
|
||||
loginSam (sam) ->
|
||||
subscribeWithPrepaid joeCode, (err, res, result) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toEqual(403)
|
||||
done()
|
||||
|
||||
it 'Will return redeemed code as part of codes list', (done) ->
|
||||
loginSam (sam) ->
|
||||
request.get "#{getURL('/db/user')}/#{sam.id}/prepaid_codes", (err, res) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toEqual(200)
|
||||
codes = JSON.parse res.body
|
||||
expect(codes.length).toEqual(1)
|
||||
done()
|
||||
|
||||
it 'Third user can redeem a prepaid code', (done) ->
|
||||
loginNewUser (user) ->
|
||||
subscribeWithPrepaid joeCode, (err, res, result) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toEqual(200)
|
||||
endDate = new moment().add(3, 'months').toISOString().substring(0, 10)
|
||||
expect(result?.stripe?.free).toEqual(endDate)
|
||||
expect(result?.purchased?.gems).toEqual(10500)
|
||||
done()
|
||||
|
||||
it 'Fourth user cannot redeem code', (done) ->
|
||||
loginNewUser (user) ->
|
||||
subscribeWithPrepaid joeCode, (err, res, result) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toEqual(403)
|
||||
done()
|
||||
|
||||
|
||||
it 'Can fetch a list of purchased and redeemed prepaid codes', (done) ->
|
||||
stripe.tokens.create {
|
||||
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
||||
}, (err, token) ->
|
||||
loginJoe (joe) ->
|
||||
purchasePrepaid 'terminal_subscription', months: 1, 3, token.id, (err, res, prepaid) ->
|
||||
request.get "#{getURL('/db/user')}/#{joe.id}/prepaid_codes", (err, res) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toEqual(200);
|
||||
codes = JSON.parse res.body
|
||||
expect(codes.length).toEqual(2)
|
||||
expect(codes[0].maxRedeemers).toEqual(3)
|
||||
expect(codes[0].properties).toBeDefined()
|
||||
expect(codes[0].properties.months).toEqual(3)
|
||||
done()
|
||||
|
||||
it 'Test for injection', (done) ->
|
||||
loginNewUser (user) ->
|
||||
code = { $exists: true }
|
||||
subscribeWithPrepaid code, (err, res, result) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).not.toEqual(200)
|
||||
done()
|
||||
# TODO: add a bunch of parallel tests trying to redeem a code with a high maxRedeemers (50?) to see what happens
|
||||
|
|
Loading…
Reference in a new issue