mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-05-23 17:19:37 +02:00
[web] Fix wrong price shown in future payments preview when upgrading over a pending downgrade (#33305)
* fix(web): show correct plan in future payments preview when upgrading over a pending downgrade When a user had a scheduled plan downgrade and then immediately upgraded to a higher plan, makeChangePreview() always used the pending (stale) plan code/name/price for the future payments display rather than the newly selected plan. Check whether the current change is a plan change (premium-subscription or group-plan-upgrade type) and if so use subscriptionChange's plan details instead of pendingChange's, since the immediate upgrade overrides the scheduled downgrade. Closes #33299 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test(web): add unit tests for makeChangePreview pending-change plan override Covers the four cases: premium-subscription and group-plan-upgrade types use subscriptionChange plan (not pendingChange), add-on-purchase type defers to pendingChange plan, and no-pending-change falls back to subscriptionChange as before. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> GitOrigin-RevId: cc2f9c88e5dfdfb89370798e857ea98caf8fcf85
This commit is contained in:
@@ -1229,11 +1229,23 @@ function makeChangePreview(
|
||||
}
|
||||
}
|
||||
|
||||
// If the current change is a plan change, it overrides the pending scheduled
|
||||
// plan change — use the new plan for future payments, not the stale pending one.
|
||||
const isPlanChange =
|
||||
subscriptionChangeDescription.type === 'premium-subscription' ||
|
||||
subscriptionChangeDescription.type === 'group-plan-upgrade'
|
||||
|
||||
futureInvoiceChange = new PaymentProviderSubscriptionChange({
|
||||
subscription,
|
||||
nextPlanCode: pendingChange.nextPlanCode,
|
||||
nextPlanName: pendingChange.nextPlanName,
|
||||
nextPlanPrice: pendingChange.nextPlanPrice,
|
||||
nextPlanCode: isPlanChange
|
||||
? subscriptionChange.nextPlanCode
|
||||
: pendingChange.nextPlanCode,
|
||||
nextPlanName: isPlanChange
|
||||
? subscriptionChange.nextPlanName
|
||||
: pendingChange.nextPlanName,
|
||||
nextPlanPrice: isPlanChange
|
||||
? subscriptionChange.nextPlanPrice
|
||||
: pendingChange.nextPlanPrice,
|
||||
nextAddOns: mergedAddOns,
|
||||
})
|
||||
} else {
|
||||
|
||||
@@ -1429,6 +1429,88 @@ describe('SubscriptionController', function () {
|
||||
})
|
||||
})
|
||||
|
||||
describe('makeChangePreview', function () {
|
||||
let pendingChange, baseSubscription, subscriptionChange
|
||||
|
||||
beforeEach(function (ctx) {
|
||||
pendingChange = {
|
||||
nextPlanCode: 'student',
|
||||
nextPlanName: 'Student',
|
||||
nextPlanPrice: 1000,
|
||||
nextAddOns: [],
|
||||
}
|
||||
|
||||
baseSubscription = {
|
||||
currency: 'USD',
|
||||
netTerms: 0,
|
||||
periodEnd: new Date('2027-04-29'),
|
||||
taxRate: 0,
|
||||
pendingChange,
|
||||
}
|
||||
|
||||
subscriptionChange = {
|
||||
subscription: baseSubscription,
|
||||
nextPlanCode: 'professional',
|
||||
nextPlanName: 'Professional',
|
||||
nextPlanPrice: 2000,
|
||||
nextAddOns: [],
|
||||
immediateCharge: {
|
||||
subtotal: 0,
|
||||
tax: 0,
|
||||
total: 0,
|
||||
discount: 0,
|
||||
lineItems: [],
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
it('uses subscriptionChange plan for future invoice when type is premium-subscription', function (ctx) {
|
||||
const preview = ctx.SubscriptionController.makeChangePreview(
|
||||
{
|
||||
type: 'premium-subscription',
|
||||
plan: { code: 'professional', name: 'Professional' },
|
||||
},
|
||||
subscriptionChange
|
||||
)
|
||||
expect(preview.nextInvoice.plan.name).to.equal('Professional')
|
||||
expect(preview.nextInvoice.plan.amount).to.equal(2000)
|
||||
})
|
||||
|
||||
it('uses subscriptionChange plan for future invoice when type is group-plan-upgrade', function (ctx) {
|
||||
const preview = ctx.SubscriptionController.makeChangePreview(
|
||||
{ type: 'group-plan-upgrade', prevPlan: { name: 'Standard' } },
|
||||
subscriptionChange
|
||||
)
|
||||
expect(preview.nextInvoice.plan.name).to.equal('Professional')
|
||||
expect(preview.nextInvoice.plan.amount).to.equal(2000)
|
||||
})
|
||||
|
||||
it('uses pendingChange plan for future invoice when type is add-on-purchase', function (ctx) {
|
||||
const preview = ctx.SubscriptionController.makeChangePreview(
|
||||
{
|
||||
type: 'add-on-purchase',
|
||||
addOn: { code: 'ai-assist', name: 'AI Assist' },
|
||||
},
|
||||
subscriptionChange
|
||||
)
|
||||
expect(preview.nextInvoice.plan.name).to.equal('Student')
|
||||
expect(preview.nextInvoice.plan.amount).to.equal(1000)
|
||||
})
|
||||
|
||||
it('uses subscriptionChange plan for future invoice when there is no pending change', function (ctx) {
|
||||
baseSubscription.pendingChange = undefined
|
||||
const preview = ctx.SubscriptionController.makeChangePreview(
|
||||
{
|
||||
type: 'premium-subscription',
|
||||
plan: { code: 'professional', name: 'Professional' },
|
||||
},
|
||||
subscriptionChange
|
||||
)
|
||||
expect(preview.nextInvoice.plan.name).to.equal('Professional')
|
||||
expect(preview.nextInvoice.plan.amount).to.equal(2000)
|
||||
})
|
||||
})
|
||||
|
||||
describe('previewAddonPurchase', function () {
|
||||
beforeEach(function (ctx) {
|
||||
ctx.req = new MockRequest(vi)
|
||||
|
||||
Reference in New Issue
Block a user