ソースを参照

Merge pull request #3665 from overleaf/cmg-jpa-members-limit-addon

Support membersLimit add on for recurly subscriptions

GitOrigin-RevId: d4256665d703e3c348cdac11af669c70f3c2feb2
Timothée Alby 5 年 前
親
コミット
450d744f9a

+ 13 - 0
services/web/app/src/Features/Subscription/SubscriptionUpdater.js

@@ -270,6 +270,19 @@ const SubscriptionUpdater = {
       }
       subscription.groupPlan = true
       subscription.membersLimit = plan.membersLimit
+
+      // Some plans allow adding more seats than the base plan provides.
+      // This is recorded as a subscription add on.
+      if (
+        plan.membersLimitAddOn &&
+        Array.isArray(recurlySubscription.subscription_add_ons)
+      ) {
+        recurlySubscription.subscription_add_ons.forEach(addOn => {
+          if (addOn.add_on_code === plan.membersLimitAddOn) {
+            subscription.membersLimit += addOn.quantity
+          }
+        })
+      }
     }
     subscription.save(function(error) {
       if (error) {

+ 17 - 1
services/web/app/src/Features/Subscription/SubscriptionViewModelBuilder.js

@@ -185,6 +185,20 @@ module.exports = {
             (recurlySubscription != null
               ? recurlySubscription.tax_in_cents
               : undefined) || 0
+          // Some plans allow adding more seats than the base plan provides.
+          // This is recorded as a subscription add on.
+          // Note: tax_in_cents already includes the tax for any addon.
+          let addOnPrice = 0
+          if (
+            plan.membersLimitAddOn &&
+            Array.isArray(recurlySubscription.subscription_add_ons)
+          ) {
+            recurlySubscription.subscription_add_ons.forEach(addOn => {
+              if (addOn.add_on_code === plan.membersLimitAddOn) {
+                addOnPrice += addOn.quantity * addOn.unit_amount_in_cents
+              }
+            })
+          }
           personalSubscription.recurly = {
             tax,
             taxRate: parseFloat(
@@ -203,7 +217,9 @@ module.exports = {
             price: SubscriptionFormatters.formatPrice(
               (recurlySubscription != null
                 ? recurlySubscription.unit_amount_in_cents
-                : undefined) + tax,
+                : undefined) +
+                addOnPrice +
+                tax,
               recurlySubscription != null
                 ? recurlySubscription.currency
                 : undefined

+ 66 - 1
services/web/test/unit/src/Subscription/SubscriptionUpdaterTests.js

@@ -3,7 +3,7 @@ const chai = require('chai')
 const sinon = require('sinon')
 const modulePath =
   '../../../../app/src/Features/Subscription/SubscriptionUpdater'
-const { assert } = require('chai')
+const { assert, expect } = require('chai')
 const { ObjectId } = require('mongodb')
 
 chai.should()
@@ -349,6 +349,71 @@ describe('SubscriptionUpdater', function() {
         }
       )
     })
+
+    describe('when the plan allows adding more seats', function() {
+      beforeEach(function() {
+        this.membersLimitAddOn = 'add_on1'
+        this.PlansLocator.findLocalPlanInSettings
+          .withArgs(this.recurlySubscription.plan.plan_code)
+          .returns({
+            groupPlan: true,
+            membersLimit: 5,
+            membersLimitAddOn: this.membersLimitAddOn
+          })
+      })
+
+      function expectMembersLimit(limit) {
+        it('should set the membersLimit accordingly', function(done) {
+          this.SubscriptionUpdater._updateSubscriptionFromRecurly(
+            this.recurlySubscription,
+            this.subscription,
+            {},
+            error => {
+              if (error) return done(error)
+
+              expect(this.subscription.membersLimit).to.equal(limit)
+              done()
+            }
+          )
+        })
+      }
+
+      describe('when the recurlySubscription does not have add ons', function() {
+        beforeEach(function() {
+          delete this.recurlySubscription.subscription_add_ons
+        })
+        expectMembersLimit(5)
+      })
+
+      describe('when the recurlySubscription has non-matching add ons', function() {
+        beforeEach(function() {
+          this.recurlySubscription.subscription_add_ons = [
+            { add_on_code: 'add_on_99', quantity: 3 }
+          ]
+        })
+        expectMembersLimit(5)
+      })
+
+      describe('when the recurlySubscription has a matching add on', function() {
+        beforeEach(function() {
+          this.recurlySubscription.subscription_add_ons = [
+            { add_on_code: this.membersLimitAddOn, quantity: 10 }
+          ]
+        })
+        expectMembersLimit(15)
+      })
+
+      // NOTE: This is unexpected, but we are going to support it anyways.
+      describe('when the recurlySubscription has multiple matching add ons', function() {
+        beforeEach(function() {
+          this.recurlySubscription.subscription_add_ons = [
+            { add_on_code: this.membersLimitAddOn, quantity: 10 },
+            { add_on_code: this.membersLimitAddOn, quantity: 3 }
+          ]
+        })
+        expectMembersLimit(18)
+      })
+    })
   })
 
   describe('_createNewSubscription', function() {