| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298 |
- const async = require('async')
- const RecurlyWrapper = require('./RecurlyWrapper')
- const { User } = require('../../models/User')
- const { promisifyAll } = require('../../util/promises')
- const logger = require('logger-sharelatex')
- const SubscriptionUpdater = require('./SubscriptionUpdater')
- const LimitationsManager = require('./LimitationsManager')
- const EmailHandler = require('../Email/EmailHandler')
- const Events = require('../../infrastructure/Events')
- const Analytics = require('../Analytics/AnalyticsManager')
- const SubscriptionHandler = {
- validateNoSubscriptionInRecurly(userId, callback) {
- if (callback == null) {
- callback = function() {}
- }
- RecurlyWrapper.listAccountActiveSubscriptions(userId, function(
- error,
- subscriptions
- ) {
- if (subscriptions == null) {
- subscriptions = []
- }
- if (error != null) {
- return callback(error)
- }
- if (subscriptions.length > 0) {
- SubscriptionUpdater.syncSubscription(subscriptions[0], userId, function(
- error
- ) {
- if (error != null) {
- return callback(error)
- }
- callback(null, false)
- })
- } else {
- callback(null, true)
- }
- })
- },
- createSubscription(user, subscriptionDetails, recurlyTokenIds, callback) {
- SubscriptionHandler.validateNoSubscriptionInRecurly(user._id, function(
- error,
- valid
- ) {
- if (error != null) {
- return callback(error)
- }
- if (!valid) {
- return callback(new Error('user already has subscription in recurly'))
- }
- RecurlyWrapper.createSubscription(
- user,
- subscriptionDetails,
- recurlyTokenIds,
- function(error, recurlySubscription) {
- if (error != null) {
- return callback(error)
- }
- return SubscriptionUpdater.syncSubscription(
- recurlySubscription,
- user._id,
- function(error) {
- if (error != null) {
- return callback(error)
- }
- return callback()
- }
- )
- }
- )
- })
- },
- updateSubscription(user, planCode, couponCode, callback) {
- LimitationsManager.userHasV2Subscription(user, function(
- err,
- hasSubscription,
- subscription
- ) {
- if (err) {
- logger.warn(
- { err, user_id: user._id, hasSubscription },
- 'there was an error checking user v2 subscription'
- )
- }
- if (!hasSubscription) {
- return callback()
- } else {
- return async.series(
- [
- function(cb) {
- if (couponCode == null) {
- return cb()
- }
- RecurlyWrapper.getSubscription(
- subscription.recurlySubscription_id,
- { includeAccount: true },
- function(err, usersSubscription) {
- if (err != null) {
- return callback(err)
- }
- RecurlyWrapper.redeemCoupon(
- usersSubscription.account.account_code,
- couponCode,
- cb
- )
- }
- )
- },
- cb =>
- RecurlyWrapper.updateSubscription(
- subscription.recurlySubscription_id,
- { plan_code: planCode, timeframe: 'now' },
- function(error, recurlySubscription) {
- if (error != null) {
- return callback(error)
- }
- SubscriptionUpdater.syncSubscription(
- recurlySubscription,
- user._id,
- cb
- )
- }
- )
- ],
- callback
- )
- }
- })
- },
- cancelSubscription(user, callback) {
- LimitationsManager.userHasV2Subscription(user, function(
- err,
- hasSubscription,
- subscription
- ) {
- if (err) {
- logger.warn(
- { err, user_id: user._id, hasSubscription },
- 'there was an error checking user v2 subscription'
- )
- }
- if (hasSubscription) {
- RecurlyWrapper.cancelSubscription(
- subscription.recurlySubscription_id,
- function(error) {
- if (error != null) {
- return callback(error)
- }
- const emailOpts = {
- to: user.email,
- first_name: user.first_name
- }
- const ONE_HOUR_IN_MS = 1000 * 60 * 60
- setTimeout(
- () =>
- EmailHandler.sendEmail(
- 'canceledSubscription',
- emailOpts,
- err => {
- if (err != null) {
- logger.warn(
- { err },
- 'failed to send confirmation email for subscription cancellation'
- )
- }
- }
- ),
- ONE_HOUR_IN_MS
- )
- Events.emit('cancelSubscription', user._id)
- Analytics.recordEvent(user._id, 'subscription-canceled')
- callback()
- }
- )
- } else {
- callback()
- }
- })
- },
- reactivateSubscription(user, callback) {
- LimitationsManager.userHasV2Subscription(user, function(
- err,
- hasSubscription,
- subscription
- ) {
- if (err) {
- logger.warn(
- { err, user_id: user._id, hasSubscription },
- 'there was an error checking user v2 subscription'
- )
- }
- if (hasSubscription) {
- RecurlyWrapper.reactivateSubscription(
- subscription.recurlySubscription_id,
- function(error) {
- if (error != null) {
- return callback(error)
- }
- EmailHandler.sendEmail(
- 'reactivatedSubscription',
- { to: user.email },
- err => {
- if (err != null) {
- logger.warn(
- { err },
- 'failed to send reactivation confirmation email'
- )
- }
- }
- )
- Analytics.recordEvent(user._id, 'subscription-reactivated')
- callback()
- }
- )
- } else {
- callback()
- }
- })
- },
- syncSubscription(recurlySubscription, requesterData, callback) {
- RecurlyWrapper.getSubscription(
- recurlySubscription.uuid,
- { includeAccount: true },
- function(error, recurlySubscription) {
- if (error != null) {
- return callback(error)
- }
- User.findById(
- recurlySubscription.account.account_code,
- { _id: 1 },
- function(error, user) {
- if (error != null) {
- return callback(error)
- }
- if (user == null) {
- return callback(new Error('no user found'))
- }
- SubscriptionUpdater.syncSubscription(
- recurlySubscription,
- user != null ? user._id : undefined,
- requesterData,
- callback
- )
- }
- )
- }
- )
- },
- // attempt to collect past due invoice for customer. Only do that when a) the
- // customer is using Paypal and b) there is only one past due invoice.
- // This is used because Recurly doesn't always attempt collection of paast due
- // invoices after Paypal billing info were updated.
- attemptPaypalInvoiceCollection(recurlyAccountCode, callback) {
- RecurlyWrapper.getBillingInfo(recurlyAccountCode, (error, billingInfo) => {
- if (error) {
- return callback(error)
- }
- if (!billingInfo.paypal_billing_agreement_id) {
- // this is not a Paypal user
- return callback()
- }
- RecurlyWrapper.getAccountPastDueInvoices(
- recurlyAccountCode,
- (error, pastDueInvoices) => {
- if (error) {
- return callback(error)
- }
- if (pastDueInvoices.length !== 1) {
- // no past due invoices, or more than one. Ignore.
- return callback()
- }
- RecurlyWrapper.attemptInvoiceCollection(
- pastDueInvoices[0].invoice_number,
- callback
- )
- }
- )
- })
- },
- extendTrial(subscription, daysToExend, callback) {
- return RecurlyWrapper.extendTrial(
- subscription.recurlySubscription_id,
- daysToExend,
- callback
- )
- }
- }
- SubscriptionHandler.promises = promisifyAll(SubscriptionHandler)
- module.exports = SubscriptionHandler
|