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

Expose past_due status to customer.io

GitOrigin-RevId: 5b1b03db0e1068f1ae444585e4a9e732470f0ffa
This commit is contained in:
roo hutton
2026-05-27 13:54:45 +01:00
committed by Copybot
parent ad193d81c5
commit 5d0becf76b
2 changed files with 87 additions and 3 deletions
@@ -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
@@ -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)
})
})
})