mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-05-23 17:19:37 +02:00
Merge pull request #27643 from overleaf/rh-pause-cancel
Terminate Recurly subscription when cancelling during final month of pause GitOrigin-RevId: 39e4c9534621f57b3e2783599ebe521959d7401f
This commit is contained in:
@@ -331,18 +331,32 @@ 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.debug(
|
||||
{ subscriptionUuid },
|
||||
'subscription cancellation failed, subscription not active'
|
||||
)
|
||||
}
|
||||
} else {
|
||||
if (!(err instanceof recurly.errors.ValidationError)) {
|
||||
throw err
|
||||
}
|
||||
|
||||
const errorMessage = err.message || ''
|
||||
|
||||
if (
|
||||
errorMessage === 'Only active and future subscriptions can be canceled.'
|
||||
) {
|
||||
logger.debug(
|
||||
{ subscriptionUuid },
|
||||
'subscription cancellation failed, subscription not active'
|
||||
)
|
||||
} else if (
|
||||
errorMessage.includes(
|
||||
'Cannot cancel a paused subscription in the last cycle of the term'
|
||||
)
|
||||
) {
|
||||
logger.debug(
|
||||
{ subscriptionUuid },
|
||||
'Terminating subscription in last cycle of paused term'
|
||||
)
|
||||
return await terminateSubscriptionByUuid(subscriptionUuid)
|
||||
}
|
||||
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -134,26 +134,19 @@ async function cancelPendingSubscriptionChange(user) {
|
||||
* @param user
|
||||
*/
|
||||
async function cancelSubscription(user) {
|
||||
try {
|
||||
const { hasSubscription, subscription } =
|
||||
await LimitationsManager.promises.userHasSubscription(user)
|
||||
if (hasSubscription && subscription != null) {
|
||||
await Modules.promises.hooks.fire('cancelPaidSubscription', 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
|
||||
)
|
||||
const { hasSubscription, subscription } =
|
||||
await LimitationsManager.promises.userHasSubscription(user)
|
||||
if (hasSubscription && subscription != null) {
|
||||
await Modules.promises.hooks.fire('cancelPaidSubscription', subscription)
|
||||
const emailOpts = {
|
||||
to: user.email,
|
||||
first_name: user.first_name,
|
||||
}
|
||||
} catch (err) {
|
||||
logger.warn(
|
||||
{ err, userId: user._id },
|
||||
'there was an error checking user v2 subscription'
|
||||
const ONE_HOUR_IN_MS = 1000 * 60 * 60
|
||||
EmailHandler.sendDeferredEmail(
|
||||
'canceledSubscription',
|
||||
emailOpts,
|
||||
ONE_HOUR_IN_MS
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import { useSubscriptionDashboardContext } from '../../../../context/subscriptio
|
||||
import OLButton from '@/shared/components/ol/ol-button'
|
||||
import { PaidSubscription } from '../../../../../../../../types/subscription/dashboard/subscription'
|
||||
import { useFeatureFlag } from '@/shared/context/split-test-context'
|
||||
import { useLocation } from '@/shared/hooks/use-location'
|
||||
|
||||
export function CancelSubscriptionButton() {
|
||||
const { t } = useTranslation()
|
||||
@@ -14,7 +13,6 @@ export function CancelSubscriptionButton() {
|
||||
setModalIdShown,
|
||||
setShowCancellation,
|
||||
} = useSubscriptionDashboardContext()
|
||||
const location = useLocation()
|
||||
|
||||
const subscription = personalSubscription as PaidSubscription
|
||||
const isInTrial =
|
||||
@@ -31,18 +29,13 @@ export function CancelSubscriptionButton() {
|
||||
useFeatureFlag('pause-subscription') &&
|
||||
!hasPendingOrActivePause &&
|
||||
planIsEligibleForPause
|
||||
const shouldContactSupport =
|
||||
subscription.payment.state === 'paused' &&
|
||||
subscription.payment.remainingPauseCycles === 0
|
||||
|
||||
function handleCancelSubscriptionClick() {
|
||||
eventTracking.sendMB('subscription-page-cancel-button-click', {
|
||||
plan_code: subscription?.planCode,
|
||||
is_trial: isInTrial,
|
||||
})
|
||||
if (shouldContactSupport) {
|
||||
location.assign('/contact')
|
||||
} else if (enablePause) {
|
||||
if (enablePause) {
|
||||
setModalIdShown('pause-subscription')
|
||||
} else {
|
||||
setShowCancellation(true)
|
||||
|
||||
@@ -516,35 +516,6 @@ describe('<ActiveSubscription />', function () {
|
||||
})
|
||||
})
|
||||
|
||||
describe('contact support for paused subscription with 0 remaining cycles', function () {
|
||||
beforeEach(function () {
|
||||
this.locationWrapperSandbox = sinon.createSandbox()
|
||||
this.locationWrapperStub = this.locationWrapperSandbox.stub(location)
|
||||
})
|
||||
|
||||
afterEach(function () {
|
||||
this.locationWrapperSandbox.restore()
|
||||
})
|
||||
|
||||
it('redirects to contact page when cancel button clicked', function () {
|
||||
const pausedSubscription = cloneDeep(annualActiveSubscription)
|
||||
pausedSubscription.payment.state = 'paused'
|
||||
pausedSubscription.payment.remainingPauseCycles = 0
|
||||
|
||||
renderActiveSubscription(pausedSubscription)
|
||||
|
||||
const button = screen.getByRole('button', {
|
||||
name: 'Cancel your subscription',
|
||||
})
|
||||
fireEvent.click(button)
|
||||
|
||||
expect(sendMBSpy).to.be.calledOnceWith(
|
||||
'subscription-page-cancel-button-click'
|
||||
)
|
||||
expect(this.locationWrapperStub.assign).to.be.calledOnceWith('/contact')
|
||||
})
|
||||
})
|
||||
|
||||
describe('group plans', function () {
|
||||
it('does not show "Change plan" option for group plans', function () {
|
||||
renderActiveSubscription(groupActiveSubscription)
|
||||
|
||||
@@ -560,6 +560,30 @@ describe('RecurlyClient', function () {
|
||||
'uuid-' + this.subscription.uuid
|
||||
)
|
||||
})
|
||||
|
||||
it('should terminate subscription when cancellation fails due to being in last cycle of paused term', async function () {
|
||||
const validationError = new recurly.errors.ValidationError()
|
||||
validationError.message =
|
||||
'Cannot cancel a paused subscription in the last cycle of the term'
|
||||
|
||||
this.client.cancelSubscription = sinon.stub().throws(validationError)
|
||||
this.client.terminateSubscription = sinon
|
||||
.stub()
|
||||
.resolves(this.recurlySubscription)
|
||||
|
||||
const subscription =
|
||||
await this.RecurlyClient.promises.cancelSubscriptionByUuid(
|
||||
this.subscription.uuid
|
||||
)
|
||||
|
||||
expect(this.client.cancelSubscription).to.be.calledWith(
|
||||
'uuid-' + this.subscription.uuid
|
||||
)
|
||||
expect(this.client.terminateSubscription).to.be.calledWith(
|
||||
'uuid-' + this.subscription.uuid
|
||||
)
|
||||
expect(subscription).to.deep.equal(this.recurlySubscription)
|
||||
})
|
||||
})
|
||||
|
||||
describe('pauseSubscriptionByUuid', function () {
|
||||
|
||||
Reference in New Issue
Block a user