[web] Fix preview next-invoice date for cadence-change upgrades (#33697)
* [web] Fix preview next-invoice date for cadence-change upgrades When upgrading from a monthly plan to an annual plan (or vice versa) the user pays for a full new-cadence term today, so the next payment is one new-term-length from now — not the current cycle's period end. Previously we always echoed subscription.periodEnd in the preview, which surfaced the stale current-cycle date and misled the user into thinking they'd be charged again ~25 days later. makeChangePreview now compares the current and next plans' annual flag: on a cadence flip it returns now + 1 year or now + 1 month; otherwise it keeps the existing behaviour. Closes #33283. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Format * Fix next invoice date using priceincents * Apply suggestions from code review Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> GitOrigin-RevId: 05b660ecb518c04b60e88f2ddc7531733245bdde
This commit is contained in:
committed by
Copybot
co-authored by
Claude Opus 4.7
Copilot Autofix powered by AI
parent
ab4f23ab86
commit
09f03381fd
@@ -49,6 +49,8 @@ const SUBSCRIPTION_PAUSED_REDIRECT_PATH =
|
||||
|
||||
/**
|
||||
* @typedef {import('../../../../types/subscription/currency').CurrencyCode} CurrencyCode
|
||||
* @typedef {import('./PaymentProviderEntities.mjs').PaymentProviderSubscription} PaymentProviderSubscription
|
||||
* @typedef {import('../../../../types/subscription/plan').Plan} Plan
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -1206,6 +1208,48 @@ function getPlanNameForDisplay(planName, planCode) {
|
||||
return `${prefix} group${suffix}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the date displayed as the user's next invoice on the preview page.
|
||||
*
|
||||
* Default: the current cycle's end (`subscription.periodEnd`).
|
||||
*
|
||||
* Exception: when the change is applied immediately AND flips cadence
|
||||
* (monthly ↔ annual), the user starts a new term today and the next invoice
|
||||
* lands one new-term-length from now. We reuse
|
||||
* `SubscriptionHelper.shouldPlanChangeAtTermEnd` so the immediate-vs-deferred
|
||||
* decision stays in step with the apply path (including the trial case).
|
||||
*
|
||||
* @param {PaymentProviderSubscription} subscription
|
||||
* @param {Plan | null | undefined} currentPlan Plan settings for the current plan, or null/undefined when unknown.
|
||||
* @param {Plan | null | undefined} nextPlan Plan settings for the post-change plan, or null/undefined when unknown.
|
||||
* @return {Date}
|
||||
*/
|
||||
function _getNextInvoiceDate(subscription, currentPlan, nextPlan) {
|
||||
if (currentPlan == null || nextPlan == null) {
|
||||
return subscription.periodEnd
|
||||
}
|
||||
const isCadenceChange =
|
||||
Boolean(currentPlan.annual) !== Boolean(nextPlan.annual)
|
||||
if (!isCadenceChange) {
|
||||
return subscription.periodEnd
|
||||
}
|
||||
const isAppliedImmediately = !SubscriptionHelper.shouldPlanChangeAtTermEnd(
|
||||
currentPlan,
|
||||
nextPlan,
|
||||
SubscriptionHelper.isInTrial(subscription.trialPeriodEnd)
|
||||
)
|
||||
if (!isAppliedImmediately) {
|
||||
return subscription.periodEnd
|
||||
}
|
||||
const nextInvoiceDate = new Date()
|
||||
if (nextPlan.annual) {
|
||||
nextInvoiceDate.setFullYear(nextInvoiceDate.getFullYear() + 1)
|
||||
} else {
|
||||
nextInvoiceDate.setMonth(nextInvoiceDate.getMonth() + 1)
|
||||
}
|
||||
return nextInvoiceDate
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a subscription change preview for display purposes
|
||||
*
|
||||
@@ -1263,6 +1307,14 @@ function makeChangePreview(
|
||||
const nextPlan = PlansLocator.findLocalPlanInSettings(
|
||||
futureInvoiceChange.nextPlanCode
|
||||
)
|
||||
const currentPlan = PlansLocator.findLocalPlanInSettings(
|
||||
subscription.planCode
|
||||
)
|
||||
const nextInvoiceDate = _getNextInvoiceDate(
|
||||
subscription,
|
||||
currentPlan,
|
||||
nextPlan
|
||||
)
|
||||
|
||||
return {
|
||||
change: subscriptionChangeDescription,
|
||||
@@ -1274,7 +1326,7 @@ function makeChangePreview(
|
||||
annual: nextPlan?.annual ?? false,
|
||||
},
|
||||
nextInvoice: {
|
||||
date: subscription.periodEnd.toISOString(),
|
||||
date: nextInvoiceDate.toISOString(),
|
||||
plan: {
|
||||
name: getPlanNameForDisplay(
|
||||
nextPlan?.name ?? futureInvoiceChange.nextPlanName,
|
||||
|
||||
Reference in New Issue
Block a user