mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-05-25 02:00:10 +02:00
[web] check end state before terminating (#31136)
* check and log unexpected end states before terminating Recurly subscriptions * update finalize and rollback scripts to only postpone active subscriptions GitOrigin-RevId: 7fe6ffa56cb8ddf19133eb0cb59e39fd783430b7
This commit is contained in:
@@ -195,25 +195,60 @@ async function processTermination(input, commit) {
|
||||
)
|
||||
}
|
||||
|
||||
// 3. If commit mode, terminate the subscription
|
||||
// 3. Fetch Recurly subscription and verify it is in our expected state
|
||||
let recurlySubscription
|
||||
let isInExpectedEndState = true
|
||||
try {
|
||||
recurlySubscription =
|
||||
await RecurlyClient.promises.getSubscription(subscriptionUuid)
|
||||
} catch (err) {
|
||||
isInExpectedEndState = false
|
||||
}
|
||||
|
||||
if (recurlySubscription) {
|
||||
const nineYearsFromNow = new Date()
|
||||
nineYearsFromNow.setFullYear(new Date().getFullYear() + 9)
|
||||
|
||||
if (
|
||||
recurlySubscription.periodEnd > nineYearsFromNow &&
|
||||
recurlySubscription.state === 'canceled'
|
||||
) {
|
||||
isInExpectedEndState = false
|
||||
}
|
||||
} else {
|
||||
throw new ReportError(
|
||||
'missing-subscription',
|
||||
'Recurly subscription not found'
|
||||
)
|
||||
}
|
||||
const warning = isInExpectedEndState
|
||||
? ''
|
||||
: `(subscription was NOT in expected state: periodEnd=${recurlySubscription?.periodEnd?.toISOString()}, state=${recurlySubscription?.state})`
|
||||
|
||||
// 4. If commit mode, terminate the subscription
|
||||
if (commit) {
|
||||
try {
|
||||
await RecurlyClient.promises.terminateSubscriptionByUuid(subscriptionUuid)
|
||||
|
||||
return {
|
||||
status: 'terminated',
|
||||
note: 'Successfully terminated Recurly subscription',
|
||||
status: isInExpectedEndState
|
||||
? 'terminated'
|
||||
: 'terminated-with-warnings',
|
||||
note: `Successfully terminated Recurly subscription ${warning}`,
|
||||
}
|
||||
} catch (err) {
|
||||
throw new ReportError(
|
||||
'terminate-failed',
|
||||
`Failed to terminate: ${err.message}`
|
||||
`Failed to terminate: ${err.message} ${warning}`
|
||||
)
|
||||
}
|
||||
} else {
|
||||
const note = isInExpectedEndState
|
||||
? 'DRY RUN: Ready to terminate'
|
||||
: `DRY RUN: Ready to terminate ${warning}`
|
||||
|
||||
return {
|
||||
status: 'validated',
|
||||
note: 'DRY RUN: Ready to terminate',
|
||||
note,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -431,21 +431,23 @@ async function performCutover(
|
||||
}
|
||||
)
|
||||
|
||||
// Step 3: Postpone Recurly billing by +10 years
|
||||
const currentBillingDate = new Date(
|
||||
recurlySubscription.current_period_ends_at
|
||||
)
|
||||
const postponedDate = new Date(currentBillingDate)
|
||||
postponedDate.setFullYear(currentBillingDate.getFullYear() + 10)
|
||||
// Step 3: Postpone Recurly billing by +10 years if Recurly subscription is active
|
||||
if (recurlySubscription.state !== 'canceled') {
|
||||
const currentBillingDate = new Date(
|
||||
recurlySubscription.current_period_ends_at
|
||||
)
|
||||
const postponedDate = new Date(currentBillingDate)
|
||||
postponedDate.setFullYear(currentBillingDate.getFullYear() + 10)
|
||||
|
||||
try {
|
||||
await RecurlyWrapper.promises.apiRequest({
|
||||
url: `subscriptions/${recurlySubscription.uuid}/postpone`,
|
||||
qs: { bulk: true, next_bill_date: postponedDate },
|
||||
method: 'PUT',
|
||||
})
|
||||
} catch (err) {
|
||||
throw new Error(`Failed to postpone Recurly billing: ${err.message}`)
|
||||
try {
|
||||
await RecurlyWrapper.promises.apiRequest({
|
||||
url: `subscriptions/${recurlySubscription.uuid}/postpone`,
|
||||
qs: { bulk: true, next_bill_date: postponedDate },
|
||||
method: 'PUT',
|
||||
})
|
||||
} catch (err) {
|
||||
throw new Error(`Failed to postpone Recurly billing: ${err.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
// Step 4: Remove migration metadata from Stripe
|
||||
|
||||
@@ -301,30 +301,35 @@ async function performRollback(
|
||||
}
|
||||
)
|
||||
|
||||
// Step 3: Un-postpone Recurly billing by 10 years
|
||||
// Step 3: Un-postpone Recurly billing by 10 years if next billing period was postponed
|
||||
const currentPeriodEnd = new Date(recurlySubscription.current_period_ends_at)
|
||||
const nextBillingDate = new Date(currentPeriodEnd)
|
||||
nextBillingDate.setFullYear(currentPeriodEnd.getFullYear() - 10)
|
||||
const targetBillingDateIsInFuture = nextBillingDate.getTime() > Date.now()
|
||||
const nineYearsFromNow = new Date()
|
||||
nineYearsFromNow.setFullYear(new Date().getFullYear() + 9)
|
||||
|
||||
if (targetBillingDateIsInFuture) {
|
||||
try {
|
||||
await RecurlyWrapper.promises.apiRequest({
|
||||
url: `subscriptions/${recurlySubscriptionId}/postpone`,
|
||||
qs: { bulk: true, next_bill_date: nextBillingDate },
|
||||
method: 'PUT',
|
||||
})
|
||||
} catch (err) {
|
||||
if (currentPeriodEnd > nineYearsFromNow) {
|
||||
const nextBillingDate = new Date(currentPeriodEnd)
|
||||
nextBillingDate.setFullYear(currentPeriodEnd.getFullYear() - 10)
|
||||
const targetBillingDateIsInFuture = nextBillingDate.getTime() > Date.now()
|
||||
|
||||
if (targetBillingDateIsInFuture) {
|
||||
try {
|
||||
await RecurlyWrapper.promises.apiRequest({
|
||||
url: `subscriptions/${recurlySubscriptionId}/postpone`,
|
||||
qs: { bulk: true, next_bill_date: nextBillingDate },
|
||||
method: 'PUT',
|
||||
})
|
||||
} catch (err) {
|
||||
throw new ReportError(
|
||||
'rolled-back-recurly-restore-failed',
|
||||
`Restored Mongo but failed to restore Recurly billing: ${err.message}`
|
||||
)
|
||||
}
|
||||
} else {
|
||||
throw new ReportError(
|
||||
'rolled-back-recurly-restore-failed',
|
||||
`Restored Mongo but failed to restore Recurly billing: ${err.message}`
|
||||
`Restored Mongo and Recurly but failed to restore Recurly billing: target next billing date is in the past (${nextBillingDate.toISOString()})`
|
||||
)
|
||||
}
|
||||
} else {
|
||||
throw new ReportError(
|
||||
'rolled-back-recurly-restore-failed',
|
||||
`Restored Mongo and Recurly but failed to restore Recurly billing: target next billing date is in the past (${nextBillingDate.toISOString()})`
|
||||
)
|
||||
}
|
||||
|
||||
// Step 4: Restore migration metadata to Stripe
|
||||
|
||||
Reference in New Issue
Block a user