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

Merge pull request #33572 from overleaf/rh-cio-past-due

Expose past_due status to customer.io

GitOrigin-RevId: 5b1b03db0e1068f1ae444585e4a9e732470f0ffa
roo hutton 2 месяцев назад
Родитель
Сommit
5d0becf76b

+ 4 - 3
services/web/app/src/Features/Subscription/CustomerIoPlanHelpers.mjs

@@ -33,13 +33,13 @@ const INACTIVE_NEXT_RENEWAL_DATE_STATES = new Set([
 const PENDING_CANCELLATION_STATES = new Set(['canceled', 'cancelled'])
 
 /**
- * @param {MongoSubscription} subscription
+ * @param {Nullable<MongoSubscription>} [subscription]
  * @returns {string}
  */
 function getSubscriptionState(subscription) {
   return (
-    subscription.recurlyStatus?.state ||
-    subscription.paymentProvider?.state ||
+    subscription?.recurlyStatus?.state ||
+    subscription?.paymentProvider?.state ||
     ''
   )
 }
@@ -585,6 +585,7 @@ function getPlanProperties({
     individual_subscription: Boolean(
       individualSubscription && !individualSubscription.groupPlan
     ),
+    past_due: getSubscriptionState(individualSubscription) === 'past_due',
   }
 
   if (trialEndDate != null) properties.trial_end_date = trialEndDate

+ 83 - 0
services/web/test/unit/src/Subscription/CustomerIoPlanHelpers.test.mjs

@@ -0,0 +1,83 @@
+import { expect } from 'vitest'
+import CustomerIoPlanHelpers from '../../../../app/src/Features/Subscription/CustomerIoPlanHelpers.mjs'
+
+describe('CustomerIoPlanHelpers', function () {
+  describe('getPlanProperties past_due', function () {
+    function buildArgs(individualSubscription) {
+      return {
+        bestSubscription: { type: 'individual' },
+        individualSubscription,
+        individualPaymentRecord: null,
+        memberGroupSubscriptions: [],
+        managedGroupSubscriptions: [],
+        userIsMemberOfGroupSubscription: false,
+        hasCommons: false,
+        writefullData: null,
+      }
+    }
+
+    it('is true when the Stripe subscription state is past_due', function () {
+      const properties = CustomerIoPlanHelpers.getPlanProperties(
+        buildArgs({
+          planCode: 'collaborator',
+          groupPlan: false,
+          paymentProvider: { service: 'stripe-us', state: 'past_due' },
+        })
+      )
+      expect(properties.past_due).to.equal(true)
+    })
+
+    it('is true when the Recurly subscription state is past_due', function () {
+      const properties = CustomerIoPlanHelpers.getPlanProperties(
+        buildArgs({
+          planCode: 'collaborator',
+          groupPlan: false,
+          recurlyStatus: { state: 'past_due' },
+        })
+      )
+      expect(properties.past_due).to.equal(true)
+    })
+
+    it("is true when a group admin's group subscription is past_due", function () {
+      const properties = CustomerIoPlanHelpers.getPlanProperties(
+        buildArgs({
+          planCode: 'group_collaborator',
+          groupPlan: true,
+          paymentProvider: { service: 'stripe-us', state: 'past_due' },
+        })
+      )
+      expect(properties.past_due).to.equal(true)
+    })
+
+    it('is false for an active Stripe subscription', function () {
+      const properties = CustomerIoPlanHelpers.getPlanProperties(
+        buildArgs({
+          planCode: 'collaborator',
+          groupPlan: false,
+          paymentProvider: { service: 'stripe-us', state: 'active' },
+        })
+      )
+      expect(properties.past_due).to.equal(false)
+    })
+
+    it('is false for cancelled, expired, paused, and trial states', function () {
+      for (const state of ['cancelled', 'expired', 'paused', 'trial']) {
+        const properties = CustomerIoPlanHelpers.getPlanProperties(
+          buildArgs({
+            planCode: 'collaborator',
+            groupPlan: false,
+            paymentProvider: { service: 'stripe-us', state },
+          })
+        )
+        expect(properties.past_due, `state=${state}`).to.equal(false)
+      }
+    })
+
+    it('is false when there is no individual subscription (free user / member-only)', function () {
+      const properties = CustomerIoPlanHelpers.getPlanProperties(
+        buildArgs(undefined)
+      )
+      expect(properties.past_due).to.equal(false)
+    })
+  })
+})