Просмотр исходного кода

Merge pull request #23314 from overleaf/ls-update-group-plan-upgrade-mapping

Update group plan upgrade mapping

GitOrigin-RevId: aca3d986477dbcf0561635dfd771413a2ba1ef15
ilkin-overleaf 1 год назад
Родитель
Сommit
fb8794921e

+ 7 - 20
services/web/app/src/Features/Subscription/RecurlyEntities.js

@@ -227,29 +227,16 @@ class RecurlySubscription {
    * Upgrade group plan with the plan code provided
    *
    * @param {string} newPlanCode
-   * @param {number} membersLimit
    * @return {RecurlySubscriptionChangeRequest}
    */
-  getRequestForGroupPlanUpgrade(newPlanCode, membersLimit) {
+  getRequestForGroupPlanUpgrade(newPlanCode) {
     // Ensure all the existing add-ons are added to the new plan
-    // Except for the additional license, which will be added below
-    const addOns = this.addOns
-      .filter(addOn => addOn.code !== 'additional-license')
-      .map(
-        addOn =>
-          new RecurlySubscriptionAddOnUpdate({
-            code: addOn.code,
-            quantity: addOn.quantity,
-          })
-      )
-
-    // Get the number of licenses from the membersLimit field in the Subscription model
-    // This is necessary because legacy group plans do not fully use add-ons to represent seats
-    addOns.push(
-      new RecurlySubscriptionAddOnUpdate({
-        code: 'additional-license',
-        quantity: membersLimit,
-      })
+    const addOns = this.addOns.map(
+      addOn =>
+        new RecurlySubscriptionAddOnUpdate({
+          code: addOn.code,
+          quantity: addOn.quantity,
+        })
     )
 
     return new RecurlySubscriptionChangeRequest({

+ 30 - 1
services/web/app/src/Features/Subscription/SubscriptionController.js

@@ -683,6 +683,31 @@ async function getLatamCountryBannerDetails(req, res) {
   return latamCountryBannerDetails
 }
 
+/**
+ * There are two sets of group plans: legacy plans and consolidated plans,
+ * and their naming conventions differ.
+ * This helper method computes the name of legacy group plans to ensure
+ * consistency with the naming of consolidated group plans.
+ *
+ * @param {string} planName
+ * @param {string} planCode
+ * @return {string}
+ */
+
+function getPlanNameForDisplay(planName, planCode) {
+  const match = planCode.match(
+    /^group_(collaborator|professional)_\d+_(enterprise|educational)$/
+  )
+
+  if (!match) return planName
+
+  const [, type, category] = match
+  const prefix = type === 'collaborator' ? 'Standard' : 'Professional'
+  const suffix = category === 'educational' ? ' Educational' : ''
+
+  return `Overleaf ${prefix} Group${suffix}`
+}
+
 /**
  * Build a subscription change preview for display purposes
  *
@@ -711,7 +736,10 @@ function makeChangePreview(
     nextInvoice: {
       date: subscription.periodEnd.toISOString(),
       plan: {
-        name: subscriptionChange.nextPlanName,
+        name: getPlanNameForDisplay(
+          subscriptionChange.nextPlanName,
+          subscriptionChange.nextPlanCode
+        ),
         amount: subscriptionChange.nextPlanPrice,
       },
       addOns: subscriptionChange.nextAddOns.map(addOn => ({
@@ -755,4 +783,5 @@ module.exports = {
   makeChangePreview,
   getRecommendedCurrency,
   getLatamCountryBannerDetails,
+  getPlanNameForDisplay,
 }

+ 6 - 20
services/web/app/src/Features/Subscription/SubscriptionGroupHandler.js

@@ -186,9 +186,7 @@ async function _getUpgradeTargetPlanCodeMaybeThrow(subscription) {
     throw new Error('Not eligible for group plan upgrade')
   }
 
-  return subscription.planCode.includes('educational')
-    ? 'group_professional_educational'
-    : 'group_professional'
+  return subscription.planCode.replace('collaborator', 'professional')
 }
 
 async function _getGroupPlanUpgradeChangeRequest(ownerId) {
@@ -196,26 +194,11 @@ async function _getGroupPlanUpgradeChangeRequest(ownerId) {
     await SubscriptionLocator.promises.getUsersSubscription(ownerId)
 
   const newPlanCode = await _getUpgradeTargetPlanCodeMaybeThrow(olSubscription)
-
   const recurlySubscription = await RecurlyClient.promises.getSubscription(
     olSubscription.recurlySubscription_id
   )
-  return recurlySubscription.getRequestForGroupPlanUpgrade(
-    newPlanCode,
-    olSubscription.membersLimit
-  )
-}
-
-function _getPlanNameForDisplay(subscription) {
-  if (/^group_collaborator_\d+_enterprise$/.test(subscription.planCode)) {
-    return 'Overleaf Standard Group'
-  }
-
-  if (/^group_collaborator_\d+_educational$/.test(subscription.planCode)) {
-    return 'Overleaf Standard Group Educational'
-  }
 
-  return subscription.planName
+  return recurlySubscription.getRequestForGroupPlanUpgrade(newPlanCode)
 }
 
 async function getGroupPlanUpgradePreview(ownerId) {
@@ -227,7 +210,10 @@ async function getGroupPlanUpgradePreview(ownerId) {
     {
       type: 'group-plan-upgrade',
       prevPlan: {
-        name: _getPlanNameForDisplay(subscriptionChange.subscription),
+        name: SubscriptionController.getPlanNameForDisplay(
+          subscriptionChange.subscription.planName,
+          subscriptionChange.subscription.planCode
+        ),
       },
     },
     subscriptionChange,

+ 15 - 7
services/web/frontend/js/features/group-management/components/upgrade-subscription/upgrade-subscription-plan-details.tsx

@@ -10,14 +10,22 @@ export const LICENSE_ADD_ON = 'additional-license'
 function UpgradeSubscriptionPlanDetails() {
   const { t } = useTranslation()
   const preview = getMeta('ol-subscriptionChangePreview')
+  const totalLicenses = getMeta('ol-totalLicenses')
 
-  const licenseUnitPrice = useMemo(
-    () =>
-      preview.nextInvoice.addOns.filter(
-        addOn => addOn.code === LICENSE_ADD_ON
-      )[0].unitAmount,
-    [preview]
-  )
+  const licenseUnitPrice = useMemo(() => {
+    const additionalLicenseAddOn = preview.nextInvoice.addOns.filter(
+      addOn => addOn.code === LICENSE_ADD_ON
+    )
+    // Legacy plans might not have additional-license add-on.
+    // Hence we need to compute unit price
+    return additionalLicenseAddOn.length > 0
+      ? additionalLicenseAddOn[0].unitAmount
+      : preview.nextInvoice.plan.amount / totalLicenses
+  }, [
+    preview.nextInvoice.addOns,
+    preview.nextInvoice.plan.amount,
+    totalLicenses,
+  ])
 
   return (
     <Card

+ 2 - 8
services/web/test/unit/src/Subscription/RecurlyEntitiesTest.js

@@ -280,19 +280,13 @@ describe('RecurlyEntities', function () {
 
       describe('getRequestForGroupPlanUpgrade()', function () {
         it('returns a correct change request', function () {
-          const changeRequest = this.subscription.getRequestForGroupPlanUpgrade(
-            'test_plan_code',
-            10
-          )
+          const changeRequest =
+            this.subscription.getRequestForGroupPlanUpgrade('test_plan_code')
           const addOns = [
             new RecurlySubscriptionAddOnUpdate({
               code: 'add-on-code',
               quantity: 1,
             }),
-            new RecurlySubscriptionAddOnUpdate({
-              code: 'additional-license',
-              quantity: 10,
-            }),
           ]
           expect(changeRequest).to.deep.equal(
             new RecurlySubscriptionChangeRequest({

+ 7 - 0
services/web/test/unit/src/Subscription/SubscriptionGroupHandlerTests.js

@@ -71,6 +71,7 @@ describe('SubscriptionGroupHandler', function () {
 
     this.SubscriptionController = {
       makeChangePreview: sinon.stub().resolves(this.changePreview),
+      getPlanNameForDisplay: sinon.stub().resolves(),
     }
 
     this.SubscriptionUpdater = {
@@ -512,6 +513,9 @@ describe('SubscriptionGroupHandler', function () {
         .stub()
         .resolves({ groupPlan: true, planCode: 'group_collaborator' })
       await this.Handler.promises.upgradeGroupPlan(this.user_id)
+      this.recurlySubscription.getRequestForGroupPlanUpgrade
+        .calledWith('group_professional')
+        .should.equal(true)
       this.RecurlyClient.promises.applySubscriptionChangeRequest
         .calledWith(this.changeRequest)
         .should.equal(true)
@@ -528,6 +532,9 @@ describe('SubscriptionGroupHandler', function () {
           planCode: 'group_collaborator_10_educational',
         })
       await this.Handler.promises.upgradeGroupPlan(this.user_id)
+      this.recurlySubscription.getRequestForGroupPlanUpgrade
+        .calledWith('group_professional_10_educational')
+        .should.equal(true)
       this.RecurlyClient.promises.applySubscriptionChangeRequest
         .calledWith(this.changeRequest)
         .should.equal(true)