Merge pull request #26566 from overleaf/rh-cio-event-segmentation

Include customer.io segmentation in recurly/stripe subscription events

GitOrigin-RevId: 54483e17eec5251ac7871d43a3aa1e074dcfe98d
This commit is contained in:
roo hutton
2025-06-30 12:11:36 +01:00
committed by Copybot
parent 28c227157e
commit 2a9d3bb168
3 changed files with 130 additions and 24 deletions

View File

@@ -145,16 +145,12 @@ async function hasUserBeenAssignedToVariant(
ignoreVersion = false
) {
try {
const { session, query = {} } = req
const { session = {}, query = {} } = req
const splitTest = await _getSplitTest(splitTestName)
const currentVersion = SplitTestUtils.getCurrentVersion(splitTest)
if (
!userId ||
!SessionManager.isUserLoggedIn(session) ||
!currentVersion?.active
) {
if (!userId || !currentVersion?.active) {
return false
}

View File

@@ -12,6 +12,16 @@ async function sendRecurlyAnalyticsEvent(event, eventData) {
return
}
const customerIoEnabled =
await SplitTestHandler.promises.hasUserBeenAssignedToVariant(
{},
userId,
'customer-io-trial-conversion',
'enabled',
true
)
eventData['customerio-integration'] = customerIoEnabled || false
switch (event) {
case 'new_subscription_notification':
await _sendSubscriptionStartedEvent(userId, eventData)
@@ -67,6 +77,7 @@ async function _sendSubscriptionResumedEvent(userId, eventData) {
plan_code: planCode,
subscriptionId,
payment_provider: 'recurly',
'customerio-integration': eventData['customerio-integration'],
}
)
AnalyticsManager.setUserPropertyForUserInBackground(
@@ -89,6 +100,7 @@ async function _sendSubscriptionPausedEvent(userId, eventData) {
plan_code: planCode,
subscriptionId,
payment_provider: 'recurly',
'customerio-integration': eventData['customerio-integration'],
}
)
AnalyticsManager.setUserPropertyForUserInBackground(
@@ -111,6 +123,7 @@ async function _sendSubscriptionStartedEvent(userId, eventData) {
has_ai_add_on: hasAiAddOn,
subscriptionId,
payment_provider: 'recurly',
'customerio-integration': eventData['customerio-integration'],
}
)
AnalyticsManager.setUserPropertyForUserInBackground(
@@ -158,6 +171,7 @@ async function _sendSubscriptionUpdatedEvent(userId, eventData) {
has_ai_add_on: hasAiAddOn,
subscriptionId,
payment_provider: 'recurly',
'customerio-integration': eventData['customerio-integration'],
}
)
AnalyticsManager.setUserPropertyForUserInBackground(
@@ -190,6 +204,7 @@ async function _sendSubscriptionCancelledEvent(userId, eventData) {
has_ai_add_on: hasAiAddOn,
subscriptionId,
payment_provider: 'recurly',
'customerio-integration': eventData['customerio-integration'],
}
)
AnalyticsManager.setUserPropertyForUserInBackground(
@@ -217,6 +232,7 @@ async function _sendSubscriptionExpiredEvent(userId, eventData) {
has_ai_add_on: hasAiAddOn,
subscriptionId,
payment_provider: 'recurly',
'customerio-integration': eventData['customerio-integration'],
}
)
AnalyticsManager.setUserPropertyForUserInBackground(
@@ -249,6 +265,7 @@ async function _sendSubscriptionRenewedEvent(userId, eventData) {
has_ai_add_on: hasAiAddOn,
subscriptionId,
payment_provider: 'recurly',
'customerio-integration': eventData['customerio-integration'],
}
)
AnalyticsManager.setUserPropertyForUserInBackground(
@@ -280,6 +297,7 @@ async function _sendSubscriptionReactivatedEvent(userId, eventData) {
has_ai_add_on: hasAiAddOn,
subscriptionId,
payment_provider: 'recurly',
'customerio-integration': eventData['customerio-integration'],
}
)
AnalyticsManager.setUserPropertyForUserInBackground(

View File

@@ -41,14 +41,15 @@ describe('RecurlyEventHandler', function () {
getAssignmentForUser: sinon.stub().resolves({
variant: 'default',
}),
hasUserBeenAssignedToVariant: sinon.stub().resolves(false),
},
}),
},
})
})
it('with new_subscription_notification - free trial', function () {
this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
it('with new_subscription_notification - free trial', async function () {
await this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
'new_subscription_notification',
this.eventData
)
@@ -63,6 +64,48 @@ describe('RecurlyEventHandler', function () {
has_ai_add_on: false,
subscriptionId: this.eventData.subscription.uuid,
payment_provider: 'recurly',
'customerio-integration': false,
}
)
sinon.assert.calledWith(
this.AnalyticsManager.setUserPropertyForUserInBackground,
this.userId,
'subscription-plan-code',
this.planCode
)
sinon.assert.calledWith(
this.AnalyticsManager.setUserPropertyForUserInBackground,
this.userId,
'subscription-state',
'active'
)
sinon.assert.calledWith(
this.AnalyticsManager.setUserPropertyForUserInBackground,
this.userId,
'subscription-is-trial',
true
)
})
it('with new_subscription_notification - free trial with customerio integration enabled', async function () {
this.SplitTestHandler.promises.hasUserBeenAssignedToVariant.resolves(true)
await this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
'new_subscription_notification',
this.eventData
)
sinon.assert.calledWith(
this.AnalyticsManager.recordEventForUserInBackground,
this.userId,
'subscription-started',
{
plan_code: this.planCode,
quantity: 1,
is_trial: true,
has_ai_add_on: false,
subscriptionId: this.eventData.subscription.uuid,
payment_provider: 'recurly',
'customerio-integration': true,
}
)
sinon.assert.calledWith(
@@ -94,7 +137,7 @@ describe('RecurlyEventHandler', function () {
sinon.assert.called(this.SubscriptionEmailHandler.sendTrialOnboardingEmail)
})
it('with new_subscription_notification - no free trial', function () {
it('with new_subscription_notification - no free trial', async function () {
this.eventData.subscription.current_period_started_at = new Date(
'2021-02-10 12:34:56'
)
@@ -103,7 +146,7 @@ describe('RecurlyEventHandler', function () {
)
this.eventData.subscription.quantity = 3
this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
await this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
'new_subscription_notification',
this.eventData
)
@@ -118,6 +161,7 @@ describe('RecurlyEventHandler', function () {
has_ai_add_on: false,
subscriptionId: this.eventData.subscription.uuid,
payment_provider: 'recurly',
'customerio-integration': false,
}
)
sinon.assert.calledWith(
@@ -134,10 +178,10 @@ describe('RecurlyEventHandler', function () {
)
})
it('with updated_subscription_notification', function () {
it('with updated_subscription_notification', async function () {
this.planCode = 'new-plan-code'
this.eventData.subscription.plan.plan_code = this.planCode
this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
await this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
'updated_subscription_notification',
this.eventData
)
@@ -152,6 +196,50 @@ describe('RecurlyEventHandler', function () {
has_ai_add_on: false,
subscriptionId: this.eventData.subscription.uuid,
payment_provider: 'recurly',
'customerio-integration': false,
}
)
sinon.assert.calledWith(
this.AnalyticsManager.setUserPropertyForUserInBackground,
this.userId,
'subscription-plan-code',
this.planCode
)
sinon.assert.calledWith(
this.AnalyticsManager.setUserPropertyForUserInBackground,
this.userId,
'subscription-state',
'active'
)
sinon.assert.calledWith(
this.AnalyticsManager.setUserPropertyForUserInBackground,
this.userId,
'subscription-is-trial',
true
)
})
it('with updated_subscription_notification with customerio integration enabled', async function () {
this.SplitTestHandler.promises.hasUserBeenAssignedToVariant.resolves(true)
this.planCode = 'new-plan-code'
this.eventData.subscription.plan.plan_code = this.planCode
await this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
'updated_subscription_notification',
this.eventData
)
sinon.assert.calledWith(
this.AnalyticsManager.recordEventForUserInBackground,
this.userId,
'subscription-updated',
{
plan_code: this.planCode,
quantity: 1,
is_trial: true,
has_ai_add_on: false,
subscriptionId: this.eventData.subscription.uuid,
payment_provider: 'recurly',
'customerio-integration': true,
}
)
sinon.assert.calledWith(
@@ -191,6 +279,7 @@ describe('RecurlyEventHandler', function () {
has_ai_add_on: false,
subscriptionId: this.eventData.subscription.uuid,
payment_provider: 'recurly',
'customerio-integration': false,
}
)
sinon.assert.calledWith(
@@ -207,9 +296,9 @@ describe('RecurlyEventHandler', function () {
)
})
it('with expired_subscription_notification', function () {
it('with expired_subscription_notification', async function () {
this.eventData.subscription.state = 'expired'
this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
await this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
'expired_subscription_notification',
this.eventData
)
@@ -224,6 +313,7 @@ describe('RecurlyEventHandler', function () {
has_ai_add_on: false,
subscriptionId: this.eventData.subscription.uuid,
payment_provider: 'recurly',
'customerio-integration': false,
}
)
sinon.assert.calledWith(
@@ -246,8 +336,8 @@ describe('RecurlyEventHandler', function () {
)
})
it('with renewed_subscription_notification', function () {
this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
it('with renewed_subscription_notification', async function () {
await this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
'renewed_subscription_notification',
this.eventData
)
@@ -262,12 +352,13 @@ describe('RecurlyEventHandler', function () {
has_ai_add_on: false,
subscriptionId: this.eventData.subscription.uuid,
payment_provider: 'recurly',
'customerio-integration': false,
}
)
})
it('with reactivated_account_notification', function () {
this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
it('with reactivated_account_notification', async function () {
await this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
'reactivated_account_notification',
this.eventData
)
@@ -281,11 +372,12 @@ describe('RecurlyEventHandler', function () {
has_ai_add_on: false,
subscriptionId: this.eventData.subscription.uuid,
payment_provider: 'recurly',
'customerio-integration': false,
}
)
})
it('with paid_charge_invoice_notification', function () {
it('with paid_charge_invoice_notification', async function () {
const invoice = {
invoice_number: 1234,
currency: 'USD',
@@ -298,7 +390,7 @@ describe('RecurlyEventHandler', function () {
collection_method: 'automatic',
subscription_ids: ['abcd1234', 'defa3214'],
}
this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
await this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
'paid_charge_invoice_notification',
{
account: {
@@ -325,8 +417,8 @@ describe('RecurlyEventHandler', function () {
)
})
it('with paid_charge_invoice_notification and total_in_cents 0', function () {
this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
it('with paid_charge_invoice_notification and total_in_cents 0', async function () {
await this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
'paid_charge_invoice_notification',
{
account: {
@@ -341,8 +433,8 @@ describe('RecurlyEventHandler', function () {
sinon.assert.notCalled(this.AnalyticsManager.recordEventForUserInBackground)
})
it('with closed_invoice_notification', function () {
this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
it('with closed_invoice_notification', async function () {
await this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
'closed_invoice_notification',
{
account: {