Merge pull request #14130 from overleaf/ab-cancel-reactivate-sub-sync-status

[web] Update subscription from Recurly when canceling/reactivating

GitOrigin-RevId: 7ba9a3d8ee41efa3435ef6d8b29c7b71f008c069
This commit is contained in:
Alexandre Bourdin 2023-08-09 11:07:10 +02:00 committed by Copybot
parent 48ee8779f0
commit 114e9bc9c8
2 changed files with 103 additions and 96 deletions

View file

@ -9,6 +9,7 @@ const LimitationsManager = require('./LimitationsManager')
const EmailHandler = require('../Email/EmailHandler')
const PlansLocator = require('./PlansLocator')
const SubscriptionHelper = require('./SubscriptionHelper')
const { callbackify } = require('../../util/promises')
function validateNoSubscriptionInRecurly(userId, callback) {
RecurlyWrapper.listAccountActiveSubscriptions(
@ -177,80 +178,62 @@ function cancelPendingSubscriptionChange(user, callback) {
)
}
function cancelSubscription(user, callback) {
LimitationsManager.userHasV2Subscription(
user,
function (err, hasSubscription, subscription) {
if (err) {
logger.warn(
{ err, userId: user._id, hasSubscription },
'there was an error checking user v2 subscription'
)
}
if (hasSubscription) {
RecurlyClient.cancelSubscriptionByUuid(
subscription.recurlySubscription_id,
function (error) {
if (error) {
return callback(error)
}
const emailOpts = {
to: user.email,
first_name: user.first_name,
}
const ONE_HOUR_IN_MS = 1000 * 60 * 60
EmailHandler.sendDeferredEmail(
'canceledSubscription',
emailOpts,
ONE_HOUR_IN_MS
)
callback()
}
)
} else {
callback()
async function cancelSubscription(user) {
try {
const { hasSubscription, subscription } =
await LimitationsManager.promises.userHasV2Subscription(user)
if (hasSubscription) {
await RecurlyClient.promises.cancelSubscriptionByUuid(
subscription.recurlySubscription_id
)
await _updateSubscriptionFromRecurly(subscription)
const emailOpts = {
to: user.email,
first_name: user.first_name,
}
const ONE_HOUR_IN_MS = 1000 * 60 * 60
EmailHandler.sendDeferredEmail(
'canceledSubscription',
emailOpts,
ONE_HOUR_IN_MS
)
}
)
} catch (err) {
logger.warn(
{ err, userId: user._id },
'there was an error checking user v2 subscription'
)
}
}
function reactivateSubscription(user, callback) {
LimitationsManager.userHasV2Subscription(
user,
function (err, hasSubscription, subscription) {
if (err) {
logger.warn(
{ err, userId: user._id, hasSubscription },
'there was an error checking user v2 subscription'
)
}
if (hasSubscription) {
RecurlyClient.reactivateSubscriptionByUuid(
subscription.recurlySubscription_id,
function (error) {
if (error) {
return callback(error)
}
EmailHandler.sendEmail(
'reactivatedSubscription',
{ to: user.email },
err => {
if (err) {
logger.warn(
{ err },
'failed to send reactivation confirmation email'
)
}
}
async function reactivateSubscription(user) {
try {
const { hasSubscription, subscription } =
await LimitationsManager.promises.userHasV2Subscription(user)
if (hasSubscription) {
await RecurlyClient.promises.reactivateSubscriptionByUuid(
subscription.recurlySubscription_id
)
await _updateSubscriptionFromRecurly(subscription)
EmailHandler.sendEmail(
'reactivatedSubscription',
{ to: user.email },
err => {
if (err) {
logger.warn(
{ err },
'failed to send reactivation confirmation email'
)
callback()
}
)
} else {
callback()
}
}
)
}
)
} catch (err) {
logger.warn(
{ err, userId: user._id },
'there was an error checking user v2 subscription'
)
}
}
function syncSubscription(recurlySubscription, requesterData, callback) {
@ -323,13 +306,24 @@ function extendTrial(subscription, daysToExend, callback) {
)
}
async function _updateSubscriptionFromRecurly(subscription) {
const recurlySubscription = await RecurlyWrapper.promises.getSubscription(
subscription.recurlySubscription_id,
{}
)
await SubscriptionUpdater.promises.updateSubscriptionFromRecurly(
recurlySubscription,
subscription
)
}
module.exports = {
validateNoSubscriptionInRecurly,
createSubscription,
updateSubscription,
cancelPendingSubscriptionChange,
cancelSubscription,
reactivateSubscription,
cancelSubscription: callbackify(cancelSubscription),
reactivateSubscription: callbackify(reactivateSubscription),
syncSubscription,
attemptPaypalInvoiceCollection,
extendTrial,
@ -338,8 +332,8 @@ module.exports = {
createSubscription: promisify(createSubscription),
updateSubscription: promisify(updateSubscription),
cancelPendingSubscriptionChange: promisify(cancelPendingSubscriptionChange),
cancelSubscription: promisify(cancelSubscription),
reactivateSubscription: promisify(reactivateSubscription),
cancelSubscription,
reactivateSubscription,
syncSubscription: promisify(syncSubscription),
attemptPaypalInvoiceCollection: promisify(attemptPaypalInvoiceCollection),
extendTrial: promisify(extendTrial),

View file

@ -89,6 +89,9 @@ describe('SubscriptionHandler', function () {
getAccountPastDueInvoices: sinon.stub().yields(),
attemptInvoiceCollection: sinon.stub().yields(),
listAccountActiveSubscriptions: sinon.stub().yields(null, []),
promises: {
getSubscription: sinon.stub().resolves(this.activeRecurlySubscription),
},
}
this.RecurlyClient = {
changeSubscriptionByUuid: sinon
@ -101,14 +104,28 @@ describe('SubscriptionHandler', function () {
.stub()
.yields(null, this.activeRecurlyClientSubscription),
cancelSubscriptionByUuid: sinon.stub().yields(),
promises: {
reactivateSubscriptionByUuid: sinon
.stub()
.resolves(this.activeRecurlyClientSubscription),
cancelSubscriptionByUuid: sinon.stub().resolves(),
},
}
this.SubscriptionUpdater = {
syncSubscription: sinon.stub().yields(),
startFreeTrial: sinon.stub().callsArgWith(1),
promises: {
updateSubscriptionFromRecurly: sinon.stub().resolves(),
},
}
this.LimitationsManager = { userHasV2Subscription: sinon.stub() }
this.LimitationsManager = {
userHasV2Subscription: sinon.stub(),
promises: {
userHasV2Subscription: sinon.stub().resolves(),
},
}
this.EmailHandler = {
sendEmail: sinon.stub(),
@ -377,7 +394,7 @@ describe('SubscriptionHandler', function () {
describe('cancelSubscription', function () {
describe('with a user without a subscription', function () {
beforeEach(function (done) {
this.LimitationsManager.userHasV2Subscription.callsArgWith(
this.LimitationsManager.promises.userHasV2Subscription.callsArgWith(
1,
null,
false,
@ -393,18 +410,18 @@ describe('SubscriptionHandler', function () {
describe('with a user with a subscription', function () {
beforeEach(function (done) {
this.LimitationsManager.userHasV2Subscription.callsArgWith(
1,
null,
true,
this.subscription
)
this.LimitationsManager.promises.userHasV2Subscription.resolves({
hasSubscription: true,
subscription: this.subscription,
})
this.SubscriptionHandler.cancelSubscription(this.user, done)
})
it('should cancel the subscription', function () {
this.RecurlyClient.cancelSubscriptionByUuid.called.should.equal(true)
this.RecurlyClient.cancelSubscriptionByUuid
this.RecurlyClient.promises.cancelSubscriptionByUuid.called.should.equal(
true
)
this.RecurlyClient.promises.cancelSubscriptionByUuid
.calledWith(this.subscription.recurlySubscription_id)
.should.equal(true)
})
@ -420,15 +437,13 @@ describe('SubscriptionHandler', function () {
})
})
describe('reactiveRecurlySubscription', function () {
describe('reactivateSubscription', function () {
describe('with a user without a subscription', function () {
beforeEach(function (done) {
this.LimitationsManager.userHasV2Subscription.callsArgWith(
1,
null,
false,
this.subscription
)
this.LimitationsManager.promises.userHasV2Subscription.resolves({
hasSubscription: false,
subscription: this.subscription,
})
this.SubscriptionHandler.reactivateSubscription(this.user, done)
})
@ -445,20 +460,18 @@ describe('SubscriptionHandler', function () {
describe('with a user with a subscription', function () {
beforeEach(function (done) {
this.LimitationsManager.userHasV2Subscription.callsArgWith(
1,
null,
true,
this.subscription
)
this.LimitationsManager.promises.userHasV2Subscription.resolves({
hasSubscription: true,
subscription: this.subscription,
})
this.SubscriptionHandler.reactivateSubscription(this.user, done)
})
it('should reactivate the subscription', function () {
this.RecurlyClient.reactivateSubscriptionByUuid.called.should.equal(
this.RecurlyClient.promises.reactivateSubscriptionByUuid.called.should.equal(
true
)
this.RecurlyClient.reactivateSubscriptionByUuid
this.RecurlyClient.promises.reactivateSubscriptionByUuid
.calledWith(this.subscription.recurlySubscription_id)
.should.equal(true)
})