mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge pull request #3971 from overleaf/tm-migrate-recurly-cancellations
Migrate cancel/reactivatation of recurly subscription to node client GitOrigin-RevId: 68a8a3eba7b653ec923d020a74a09e49efa8ba21
This commit is contained in:
parent
a5e905f730
commit
6583d6de21
6 changed files with 75 additions and 133 deletions
|
@ -67,6 +67,29 @@ async function removeSubscriptionChangeByUuid(subscriptionUuid) {
|
||||||
return await removeSubscriptionChange('uuid-' + subscriptionUuid)
|
return await removeSubscriptionChange('uuid-' + subscriptionUuid)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function reactivateSubscriptionByUuid(subscriptionUuid) {
|
||||||
|
return await client.reactivateSubscription('uuid-' + subscriptionUuid)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function cancelSubscriptionByUuid(subscriptionUuid) {
|
||||||
|
try {
|
||||||
|
return await client.cancelSubscription('uuid-' + subscriptionUuid)
|
||||||
|
} catch (err) {
|
||||||
|
if (err instanceof recurly.errors.ValidationError) {
|
||||||
|
if (
|
||||||
|
err.message === 'Only active and future subscriptions can be canceled.'
|
||||||
|
) {
|
||||||
|
logger.log(
|
||||||
|
{ subscriptionUuid },
|
||||||
|
'subscription cancellation failed, subscription not active'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
errors: recurly.errors,
|
errors: recurly.errors,
|
||||||
|
|
||||||
|
@ -77,6 +100,8 @@ module.exports = {
|
||||||
changeSubscriptionByUuid: callbackify(changeSubscriptionByUuid),
|
changeSubscriptionByUuid: callbackify(changeSubscriptionByUuid),
|
||||||
removeSubscriptionChange: callbackify(removeSubscriptionChange),
|
removeSubscriptionChange: callbackify(removeSubscriptionChange),
|
||||||
removeSubscriptionChangeByUuid: callbackify(removeSubscriptionChangeByUuid),
|
removeSubscriptionChangeByUuid: callbackify(removeSubscriptionChangeByUuid),
|
||||||
|
reactivateSubscriptionByUuid: callbackify(reactivateSubscriptionByUuid),
|
||||||
|
cancelSubscriptionByUuid: callbackify(cancelSubscriptionByUuid),
|
||||||
|
|
||||||
promises: {
|
promises: {
|
||||||
getSubscription,
|
getSubscription,
|
||||||
|
@ -86,5 +111,7 @@ module.exports = {
|
||||||
changeSubscriptionByUuid,
|
changeSubscriptionByUuid,
|
||||||
removeSubscriptionChange,
|
removeSubscriptionChange,
|
||||||
removeSubscriptionChangeByUuid,
|
removeSubscriptionChangeByUuid,
|
||||||
|
reactivateSubscriptionByUuid,
|
||||||
|
cancelSubscriptionByUuid,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -770,49 +770,6 @@ const RecurlyWrapper = {
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
cancelSubscription(subscriptionId, callback) {
|
|
||||||
logger.log({ subscriptionId }, 'telling recurly to cancel subscription')
|
|
||||||
return RecurlyWrapper.apiRequest(
|
|
||||||
{
|
|
||||||
url: `subscriptions/${subscriptionId}/cancel`,
|
|
||||||
method: 'put',
|
|
||||||
},
|
|
||||||
function (error, response, body) {
|
|
||||||
if (error != null) {
|
|
||||||
return RecurlyWrapper._parseXml(body, function (_err, parsed) {
|
|
||||||
if (
|
|
||||||
__guard__(
|
|
||||||
parsed != null ? parsed.error : undefined,
|
|
||||||
x1 => x1.description
|
|
||||||
) === "A canceled subscription can't transition to canceled"
|
|
||||||
) {
|
|
||||||
// subscription already cancelled, not really an error, proceeding
|
|
||||||
return callback(null)
|
|
||||||
} else {
|
|
||||||
return callback(error)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
return callback(null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
},
|
|
||||||
|
|
||||||
reactivateSubscription(subscriptionId, callback) {
|
|
||||||
logger.log(
|
|
||||||
{ subscriptionId },
|
|
||||||
'telling recurly to reactivating subscription'
|
|
||||||
)
|
|
||||||
return RecurlyWrapper.apiRequest(
|
|
||||||
{
|
|
||||||
url: `subscriptions/${subscriptionId}/reactivate`,
|
|
||||||
method: 'put',
|
|
||||||
},
|
|
||||||
(error, response, body) => callback(error)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
|
|
||||||
redeemCoupon(account_code, coupon_code, callback) {
|
redeemCoupon(account_code, coupon_code, callback) {
|
||||||
const data = {
|
const data = {
|
||||||
account_code,
|
account_code,
|
||||||
|
|
|
@ -193,7 +193,7 @@ const SubscriptionHandler = {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (hasSubscription) {
|
if (hasSubscription) {
|
||||||
RecurlyWrapper.cancelSubscription(
|
RecurlyClient.cancelSubscriptionByUuid(
|
||||||
subscription.recurlySubscription_id,
|
subscription.recurlySubscription_id,
|
||||||
function (error) {
|
function (error) {
|
||||||
if (error != null) {
|
if (error != null) {
|
||||||
|
@ -242,7 +242,7 @@ const SubscriptionHandler = {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (hasSubscription) {
|
if (hasSubscription) {
|
||||||
RecurlyWrapper.reactivateSubscription(
|
RecurlyClient.reactivateSubscriptionByUuid(
|
||||||
subscription.recurlySubscription_id,
|
subscription.recurlySubscription_id,
|
||||||
function (error) {
|
function (error) {
|
||||||
if (error != null) {
|
if (error != null) {
|
||||||
|
|
|
@ -264,4 +264,36 @@ describe('RecurlyClient', function () {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('reactivateSubscriptionByUuid', function () {
|
||||||
|
it('should attempt to reactivate the subscription', async function () {
|
||||||
|
this.client.reactivateSubscription = sinon
|
||||||
|
.stub()
|
||||||
|
.resolves(this.recurlySubscription)
|
||||||
|
await expect(
|
||||||
|
this.RecurlyClient.promises.reactivateSubscriptionByUuid(
|
||||||
|
this.subscription.uuid
|
||||||
|
)
|
||||||
|
).to.eventually.be.an.instanceOf(recurly.Subscription)
|
||||||
|
expect(this.client.reactivateSubscription).to.be.calledWith(
|
||||||
|
'uuid-' + this.subscription.uuid
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('cancelSubscriptionByUuid', function () {
|
||||||
|
it('should attempt to cancel the subscription', async function () {
|
||||||
|
this.client.cancelSubscription = sinon
|
||||||
|
.stub()
|
||||||
|
.resolves(this.recurlySubscription)
|
||||||
|
await expect(
|
||||||
|
this.RecurlyClient.promises.cancelSubscriptionByUuid(
|
||||||
|
this.subscription.uuid
|
||||||
|
)
|
||||||
|
).to.eventually.be.an.instanceOf(recurly.Subscription)
|
||||||
|
expect(this.client.cancelSubscription).to.be.calledWith(
|
||||||
|
'uuid-' + this.subscription.uuid
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -334,86 +334,6 @@ describe('RecurlyWrapper', function () {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('cancelSubscription', function () {
|
|
||||||
beforeEach(function (done) {
|
|
||||||
this.recurlySubscriptionId = 'subscription-id-123'
|
|
||||||
this.apiRequest = sinon
|
|
||||||
.stub(this.RecurlyWrapper, 'apiRequest')
|
|
||||||
.callsFake((options, callback) => {
|
|
||||||
options.url.should.equal(
|
|
||||||
`subscriptions/${this.recurlySubscriptionId}/cancel`
|
|
||||||
)
|
|
||||||
options.method.should.equal('put')
|
|
||||||
return callback()
|
|
||||||
})
|
|
||||||
return this.RecurlyWrapper.cancelSubscription(
|
|
||||||
this.recurlySubscriptionId,
|
|
||||||
done
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
afterEach(function () {
|
|
||||||
return this.RecurlyWrapper.apiRequest.restore()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should send a cancel request to the API', function () {
|
|
||||||
return this.apiRequest.called.should.equal(true)
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('when the subscription is already cancelled', function () {
|
|
||||||
beforeEach(function () {
|
|
||||||
this.RecurlyWrapper.apiRequest.restore()
|
|
||||||
this.recurlySubscriptionId = 'subscription-id-123'
|
|
||||||
return (this.apiRequest = sinon
|
|
||||||
.stub(this.RecurlyWrapper, 'apiRequest')
|
|
||||||
.callsFake((options, callback) => {
|
|
||||||
return callback(
|
|
||||||
new Error('woops'),
|
|
||||||
{},
|
|
||||||
"<error><description>A canceled subscription can't transition to canceled</description></error>"
|
|
||||||
)
|
|
||||||
}))
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should not produce an error', function (done) {
|
|
||||||
return this.RecurlyWrapper.cancelSubscription(
|
|
||||||
this.recurlySubscriptionId,
|
|
||||||
err => {
|
|
||||||
expect(err).to.equal(null)
|
|
||||||
return done()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('reactivateSubscription', function () {
|
|
||||||
beforeEach(function (done) {
|
|
||||||
this.recurlySubscriptionId = 'subscription-id-123'
|
|
||||||
this.apiRequest = sinon
|
|
||||||
.stub(this.RecurlyWrapper, 'apiRequest')
|
|
||||||
.callsFake((options, callback) => {
|
|
||||||
options.url.should.equal(
|
|
||||||
`subscriptions/${this.recurlySubscriptionId}/reactivate`
|
|
||||||
)
|
|
||||||
options.method.should.equal('put')
|
|
||||||
return callback()
|
|
||||||
})
|
|
||||||
return this.RecurlyWrapper.reactivateSubscription(
|
|
||||||
this.recurlySubscriptionId,
|
|
||||||
done
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
afterEach(function () {
|
|
||||||
return this.RecurlyWrapper.apiRequest.restore()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should send a cancel request to the API', function () {
|
|
||||||
return this.apiRequest.called.should.equal(true)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('redeemCoupon', function () {
|
describe('redeemCoupon', function () {
|
||||||
beforeEach(function (done) {
|
beforeEach(function (done) {
|
||||||
this.recurlyAccountId = 'account-id-123'
|
this.recurlyAccountId = 'account-id-123'
|
||||||
|
|
|
@ -78,8 +78,6 @@ describe('SubscriptionHandler', function () {
|
||||||
getSubscription: sinon
|
getSubscription: sinon
|
||||||
.stub()
|
.stub()
|
||||||
.callsArgWith(2, null, this.activeRecurlySubscription),
|
.callsArgWith(2, null, this.activeRecurlySubscription),
|
||||||
cancelSubscription: sinon.stub().callsArgWith(1),
|
|
||||||
reactivateSubscription: sinon.stub().callsArgWith(1),
|
|
||||||
redeemCoupon: sinon.stub().callsArgWith(2),
|
redeemCoupon: sinon.stub().callsArgWith(2),
|
||||||
createSubscription: sinon
|
createSubscription: sinon
|
||||||
.stub()
|
.stub()
|
||||||
|
@ -95,6 +93,10 @@ describe('SubscriptionHandler', function () {
|
||||||
getSubscription: sinon
|
getSubscription: sinon
|
||||||
.stub()
|
.stub()
|
||||||
.yields(null, this.activeRecurlyClientSubscription),
|
.yields(null, this.activeRecurlyClientSubscription),
|
||||||
|
reactivateSubscriptionByUuid: sinon
|
||||||
|
.stub()
|
||||||
|
.yields(null, this.activeRecurlyClientSubscription),
|
||||||
|
cancelSubscriptionByUuid: sinon.stub().yields(),
|
||||||
}
|
}
|
||||||
|
|
||||||
this.SubscriptionUpdater = {
|
this.SubscriptionUpdater = {
|
||||||
|
@ -389,7 +391,7 @@ describe('SubscriptionHandler', function () {
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should redirect to the subscription dashboard', function () {
|
it('should redirect to the subscription dashboard', function () {
|
||||||
this.RecurlyWrapper.cancelSubscription.called.should.equal(false)
|
this.RecurlyClient.cancelSubscriptionByUuid.called.should.equal(false)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -405,8 +407,8 @@ describe('SubscriptionHandler', function () {
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should cancel the subscription', function () {
|
it('should cancel the subscription', function () {
|
||||||
this.RecurlyWrapper.cancelSubscription.called.should.equal(true)
|
this.RecurlyClient.cancelSubscriptionByUuid.called.should.equal(true)
|
||||||
this.RecurlyWrapper.cancelSubscription
|
this.RecurlyClient.cancelSubscriptionByUuid
|
||||||
.calledWith(this.subscription.recurlySubscription_id)
|
.calledWith(this.subscription.recurlySubscription_id)
|
||||||
.should.equal(true)
|
.should.equal(true)
|
||||||
})
|
})
|
||||||
|
@ -426,7 +428,9 @@ describe('SubscriptionHandler', function () {
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should redirect to the subscription dashboard', function () {
|
it('should redirect to the subscription dashboard', function () {
|
||||||
this.RecurlyWrapper.reactivateSubscription.called.should.equal(false)
|
this.RecurlyClient.reactivateSubscriptionByUuid.called.should.equal(
|
||||||
|
false
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should not send a notification email', function () {
|
it('should not send a notification email', function () {
|
||||||
|
@ -446,8 +450,10 @@ describe('SubscriptionHandler', function () {
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should reactivate the subscription', function () {
|
it('should reactivate the subscription', function () {
|
||||||
this.RecurlyWrapper.reactivateSubscription.called.should.equal(true)
|
this.RecurlyClient.reactivateSubscriptionByUuid.called.should.equal(
|
||||||
this.RecurlyWrapper.reactivateSubscription
|
true
|
||||||
|
)
|
||||||
|
this.RecurlyClient.reactivateSubscriptionByUuid
|
||||||
.calledWith(this.subscription.recurlySubscription_id)
|
.calledWith(this.subscription.recurlySubscription_id)
|
||||||
.should.equal(true)
|
.should.equal(true)
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in a new issue