From 757735b07518ffc157ae3b2abe8307beb14198a2 Mon Sep 17 00:00:00 2001 From: roo hutton Date: Fri, 5 Jun 2026 08:46:26 +0100 Subject: [PATCH] Merge pull request #34297 from overleaf/rh-prev-plan-type-cancel Update previous_plan_type on subscription expiry GitOrigin-RevId: 19381e5516fdbfd2650a9a5b94b61791e0da909f --- .../Subscription/SubscriptionUpdater.mjs | 23 ++++++++++ .../Subscription/SubscriptionUpdater.test.mjs | 42 +++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/services/web/app/src/Features/Subscription/SubscriptionUpdater.mjs b/services/web/app/src/Features/Subscription/SubscriptionUpdater.mjs index 4329a776e3..158afc9b49 100644 --- a/services/web/app/src/Features/Subscription/SubscriptionUpdater.mjs +++ b/services/web/app/src/Features/Subscription/SubscriptionUpdater.mjs @@ -508,10 +508,33 @@ async function handleExpiredSubscription(subscription, requesterData) { ) } else { await deleteSubscription(subscription, requesterData) + _setPreviousPlanTypeOnExpiry(subscription) } } } +function _setPreviousPlanTypeOnExpiry(subscription) { + const previousPlanType = CustomerIoPlanHelpers.normalizePlanType({ + plan: { + planCode: subscription.planCode, + groupPlan: subscription.groupPlan, + }, + }) + if (!previousPlanType) { + return + } + Modules.promises.hooks + .fire('setUserProperties', subscription.admin_id, { + previous_plan_type: previousPlanType, + }) + .catch(err => { + logger.warn( + { err, userId: subscription.admin_id }, + 'Failed to set previous_plan_type in customer.io' + ) + }) +} + async function _sendSubscriptionEvent(userId, subscriptionId, event) { const subscription = await Subscription.findOne( { _id: subscriptionId }, diff --git a/services/web/test/unit/src/Subscription/SubscriptionUpdater.test.mjs b/services/web/test/unit/src/Subscription/SubscriptionUpdater.test.mjs index 1b86784a59..bcc7ed68c2 100644 --- a/services/web/test/unit/src/Subscription/SubscriptionUpdater.test.mjs +++ b/services/web/test/unit/src/Subscription/SubscriptionUpdater.test.mjs @@ -707,6 +707,48 @@ describe('SubscriptionUpdater', function () { }) }) + describe('handleExpiredSubscription', function () { + it("should set the admin's previous_plan_type in customer.io to the expired plan when the subscription is deleted", async function (ctx) { + await ctx.SubscriptionUpdater.promises.handleExpiredSubscription( + ctx.subscription, + {} + ) + expect(ctx.Modules.promises.hooks.fire).to.have.been.calledWith( + 'setUserProperties', + ctx.subscription.admin_id, + { previous_plan_type: 'student' } + ) + }) + + it('should not set previous_plan_type when the subscription is not deleted (managed users)', async function (ctx) { + ctx.Features.hasFeature.withArgs('saas').returns(true) + ctx.subscription.managedUsersEnabled = true + await ctx.SubscriptionUpdater.promises.handleExpiredSubscription( + ctx.subscription, + {} + ) + expect(ctx.Modules.promises.hooks.fire).to.not.have.been.calledWith( + 'setUserProperties', + ctx.subscription.admin_id, + { previous_plan_type: 'student' } + ) + }) + + it('should not set previous_plan_type when the subscription is not deleted (group SSO)', async function (ctx) { + ctx.Features.hasFeature.withArgs('saas').returns(true) + ctx.subscription.ssoConfig = new ObjectId('abc123abc123abc123abc123') + await ctx.SubscriptionUpdater.promises.handleExpiredSubscription( + ctx.subscription, + {} + ) + expect(ctx.Modules.promises.hooks.fire).to.not.have.been.calledWith( + 'setUserProperties', + ctx.subscription.admin_id, + { previous_plan_type: 'student' } + ) + }) + }) + describe('addUserToGroup', function () { it('should add the user ids to the group as a set', async function (ctx) { ctx.SubscriptionModel.findOne = sinon