Explorar o código

Merge pull request #12811 from overleaf/jk-plans-event-currency-segmentation

[web] Add currency/id segmentation to Recurly analytics events

GitOrigin-RevId: 56998f403358d5f6b3cece6835e16e65e06635b1
June Kelly %!s(int64=3) %!d(string=hai) anos
pai
achega
e89b4b4214

+ 50 - 7
services/web/app/src/Features/Subscription/RecurlyEventHandler.js

@@ -2,6 +2,8 @@ const AnalyticsManager = require('../Analytics/AnalyticsManager')
 const SubscriptionEmailHandler = require('./SubscriptionEmailHandler')
 const SubscriptionEmailHandler = require('./SubscriptionEmailHandler')
 const { ObjectID } = require('mongodb')
 const { ObjectID } = require('mongodb')
 
 
+const INVOICE_SUBSCRIPTION_LIMIT = 10
+
 async function sendRecurlyAnalyticsEvent(event, eventData) {
 async function sendRecurlyAnalyticsEvent(event, eventData) {
   const userId = _getUserId(eventData)
   const userId = _getUserId(eventData)
   if (!ObjectID.isValid(userId)) {
   if (!ObjectID.isValid(userId)) {
@@ -47,11 +49,13 @@ async function sendRecurlyAnalyticsEvent(event, eventData) {
 }
 }
 
 
 async function _sendSubscriptionStartedEvent(userId, eventData) {
 async function _sendSubscriptionStartedEvent(userId, eventData) {
-  const { planCode, quantity, state, isTrial } = _getSubscriptionData(eventData)
+  const { planCode, quantity, state, isTrial, subscriptionId } =
+    _getSubscriptionData(eventData)
   AnalyticsManager.recordEventForUser(userId, 'subscription-started', {
   AnalyticsManager.recordEventForUser(userId, 'subscription-started', {
     plan_code: planCode,
     plan_code: planCode,
     quantity,
     quantity,
     is_trial: isTrial,
     is_trial: isTrial,
+    subscriptionId,
   })
   })
   AnalyticsManager.setUserPropertyForUser(
   AnalyticsManager.setUserPropertyForUser(
     userId,
     userId,
@@ -71,11 +75,13 @@ async function _sendSubscriptionStartedEvent(userId, eventData) {
 }
 }
 
 
 async function _sendSubscriptionUpdatedEvent(userId, eventData) {
 async function _sendSubscriptionUpdatedEvent(userId, eventData) {
-  const { planCode, quantity, state, isTrial } = _getSubscriptionData(eventData)
+  const { planCode, quantity, state, isTrial, subscriptionId } =
+    _getSubscriptionData(eventData)
   AnalyticsManager.recordEventForUser(userId, 'subscription-updated', {
   AnalyticsManager.recordEventForUser(userId, 'subscription-updated', {
     plan_code: planCode,
     plan_code: planCode,
     quantity,
     quantity,
     is_trial: isTrial,
     is_trial: isTrial,
+    subscriptionId,
   })
   })
   AnalyticsManager.setUserPropertyForUser(
   AnalyticsManager.setUserPropertyForUser(
     userId,
     userId,
@@ -91,11 +97,13 @@ async function _sendSubscriptionUpdatedEvent(userId, eventData) {
 }
 }
 
 
 async function _sendSubscriptionCancelledEvent(userId, eventData) {
 async function _sendSubscriptionCancelledEvent(userId, eventData) {
-  const { planCode, quantity, state, isTrial } = _getSubscriptionData(eventData)
+  const { planCode, quantity, state, isTrial, subscriptionId } =
+    _getSubscriptionData(eventData)
   AnalyticsManager.recordEventForUser(userId, 'subscription-cancelled', {
   AnalyticsManager.recordEventForUser(userId, 'subscription-cancelled', {
     plan_code: planCode,
     plan_code: planCode,
     quantity,
     quantity,
     is_trial: isTrial,
     is_trial: isTrial,
+    subscriptionId,
   })
   })
   AnalyticsManager.setUserPropertyForUser(userId, 'subscription-state', state)
   AnalyticsManager.setUserPropertyForUser(userId, 'subscription-state', state)
   AnalyticsManager.setUserPropertyForUser(
   AnalyticsManager.setUserPropertyForUser(
@@ -106,11 +114,13 @@ async function _sendSubscriptionCancelledEvent(userId, eventData) {
 }
 }
 
 
 async function _sendSubscriptionExpiredEvent(userId, eventData) {
 async function _sendSubscriptionExpiredEvent(userId, eventData) {
-  const { planCode, quantity, state, isTrial } = _getSubscriptionData(eventData)
+  const { planCode, quantity, state, isTrial, subscriptionId } =
+    _getSubscriptionData(eventData)
   AnalyticsManager.recordEventForUser(userId, 'subscription-expired', {
   AnalyticsManager.recordEventForUser(userId, 'subscription-expired', {
     plan_code: planCode,
     plan_code: planCode,
     quantity,
     quantity,
     is_trial: isTrial,
     is_trial: isTrial,
+    subscriptionId,
   })
   })
   AnalyticsManager.setUserPropertyForUser(
   AnalyticsManager.setUserPropertyForUser(
     userId,
     userId,
@@ -126,11 +136,13 @@ async function _sendSubscriptionExpiredEvent(userId, eventData) {
 }
 }
 
 
 async function _sendSubscriptionRenewedEvent(userId, eventData) {
 async function _sendSubscriptionRenewedEvent(userId, eventData) {
-  const { planCode, quantity, state, isTrial } = _getSubscriptionData(eventData)
+  const { planCode, quantity, state, isTrial, subscriptionId } =
+    _getSubscriptionData(eventData)
   AnalyticsManager.recordEventForUser(userId, 'subscription-renewed', {
   AnalyticsManager.recordEventForUser(userId, 'subscription-renewed', {
     plan_code: planCode,
     plan_code: planCode,
     quantity,
     quantity,
     is_trial: isTrial,
     is_trial: isTrial,
+    subscriptionId,
   })
   })
   AnalyticsManager.setUserPropertyForUser(
   AnalyticsManager.setUserPropertyForUser(
     userId,
     userId,
@@ -146,10 +158,12 @@ async function _sendSubscriptionRenewedEvent(userId, eventData) {
 }
 }
 
 
 async function _sendSubscriptionReactivatedEvent(userId, eventData) {
 async function _sendSubscriptionReactivatedEvent(userId, eventData) {
-  const { planCode, quantity, state, isTrial } = _getSubscriptionData(eventData)
+  const { planCode, quantity, state, isTrial, subscriptionId } =
+    _getSubscriptionData(eventData)
   AnalyticsManager.recordEventForUser(userId, 'subscription-reactivated', {
   AnalyticsManager.recordEventForUser(userId, 'subscription-reactivated', {
     plan_code: planCode,
     plan_code: planCode,
     quantity,
     quantity,
+    subscriptionId,
   })
   })
   AnalyticsManager.setUserPropertyForUser(
   AnalyticsManager.setUserPropertyForUser(
     userId,
     userId,
@@ -165,7 +179,35 @@ async function _sendSubscriptionReactivatedEvent(userId, eventData) {
 }
 }
 
 
 async function _sendInvoicePaidEvent(userId, eventData) {
 async function _sendInvoicePaidEvent(userId, eventData) {
-  AnalyticsManager.recordEventForUser(userId, 'subscription-invoice-collected')
+  const invoice = eventData.invoice
+  if (!invoice) {
+    return
+  }
+  const invoiceNumber = invoice.invoice_number
+  const currency = invoice.currency
+  const totalInCents = invoice.total_in_cents
+  const taxInCents = invoice.tax_in_cents
+  const country = invoice.address?.country
+  const collectionMethod = invoice.collection_method
+  const subscriptionIds = {}
+  invoice.subscription_ids?.forEach((e, idx) => {
+    if (idx < INVOICE_SUBSCRIPTION_LIMIT) {
+      subscriptionIds[`subscriptionId${idx + 1}`] = e
+    }
+  })
+  AnalyticsManager.recordEventForUser(
+    userId,
+    'subscription-invoice-collected',
+    {
+      invoiceNumber,
+      currency,
+      totalInCents,
+      taxInCents,
+      country,
+      collectionMethod,
+      ...subscriptionIds,
+    }
+  )
   AnalyticsManager.setUserPropertyForUser(
   AnalyticsManager.setUserPropertyForUser(
     userId,
     userId,
     'subscription-is-trial',
     'subscription-is-trial',
@@ -195,6 +237,7 @@ function _getSubscriptionData(eventData) {
     planCode: eventData.subscription.plan.plan_code,
     planCode: eventData.subscription.plan.plan_code,
     quantity: eventData.subscription.quantity,
     quantity: eventData.subscription.quantity,
     state: eventData.subscription.state,
     state: eventData.subscription.state,
+    subscriptionId: eventData.subscription.uuid,
     isTrial,
     isTrial,
   }
   }
 }
 }

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

@@ -69,7 +69,9 @@ async function plansPage(req, res) {
     usage: getDefault('usage', 'usage', 'enterprise'),
     usage: getDefault('usage', 'usage', 'enterprise'),
   }
   }
 
 
-  AnalyticsManager.recordEventForSession(req.session, 'plans-page-view')
+  AnalyticsManager.recordEventForSession(req.session, 'plans-page-view', {
+    currency: recommendedCurrency,
+  })
 
 
   res.render('subscriptions/plans-marketing-v2', {
   res.render('subscriptions/plans-marketing-v2', {
     title: 'plans_and_pricing',
     title: 'plans_and_pricing',

+ 5 - 1
services/web/frontend/js/features/subscription/context/payment-context.tsx

@@ -95,7 +95,10 @@ function usePayment({ publicKey }: RecurlyOptions) {
       return
       return
     }
     }
 
 
-    eventTracking.sendMB('payment-page-view', { plan: planCode })
+    eventTracking.sendMB('payment-page-view', {
+      plan: planCode,
+      currency: currencyCode,
+    })
     eventTracking.send(
     eventTracking.send(
       'subscription-funnel',
       'subscription-funnel',
       'subscription-form-viewed',
       'subscription-form-viewed',
@@ -147,6 +150,7 @@ function usePayment({ publicKey }: RecurlyOptions) {
     initiallySelectedCurrencyCode,
     initiallySelectedCurrencyCode,
     planCode,
     planCode,
     publicKey,
     publicKey,
+    currencyCode,
     t,
     t,
   ])
   ])
 
 

+ 4 - 1
services/web/frontend/js/main/new-subscription.js

@@ -76,7 +76,10 @@ export default App.controller(
         `&itm_referrer=${window.ITMReferrer}`
         `&itm_referrer=${window.ITMReferrer}`
     }
     }
 
 
-    eventTracking.sendMB('payment-page-view', { plan: window.plan_code })
+    eventTracking.sendMB('payment-page-view', {
+      plan: window.plan_code,
+      currency: $scope.currencyCode,
+    })
     eventTracking.send(
     eventTracking.send(
       'subscription-funnel',
       'subscription-funnel',
       'subscription-form-viewed',
       'subscription-form-viewed',

+ 32 - 5
services/web/test/unit/src/Subscription/RecurlyEventHandlerTests.js

@@ -12,6 +12,7 @@ describe('RecurlyEventHandler', function () {
         account_code: this.userId,
         account_code: this.userId,
       },
       },
       subscription: {
       subscription: {
+        uuid: '8435ad98c1ce45da99b07f6a6a2e780f',
         plan: {
         plan: {
           plan_code: 'collaborator-annual',
           plan_code: 'collaborator-annual',
         },
         },
@@ -50,6 +51,7 @@ describe('RecurlyEventHandler', function () {
         plan_code: this.planCode,
         plan_code: this.planCode,
         quantity: 1,
         quantity: 1,
         is_trial: true,
         is_trial: true,
+        subscriptionId: this.eventData.subscription.uuid,
       }
       }
     )
     )
     sinon.assert.calledWith(
     sinon.assert.calledWith(
@@ -102,6 +104,7 @@ describe('RecurlyEventHandler', function () {
         plan_code: this.planCode,
         plan_code: this.planCode,
         quantity: 3,
         quantity: 3,
         is_trial: false,
         is_trial: false,
+        subscriptionId: this.eventData.subscription.uuid,
       }
       }
     )
     )
     sinon.assert.calledWith(
     sinon.assert.calledWith(
@@ -133,6 +136,7 @@ describe('RecurlyEventHandler', function () {
         plan_code: this.planCode,
         plan_code: this.planCode,
         quantity: 1,
         quantity: 1,
         is_trial: true,
         is_trial: true,
+        subscriptionId: this.eventData.subscription.uuid,
       }
       }
     )
     )
     sinon.assert.calledWith(
     sinon.assert.calledWith(
@@ -169,6 +173,7 @@ describe('RecurlyEventHandler', function () {
         plan_code: this.planCode,
         plan_code: this.planCode,
         quantity: 1,
         quantity: 1,
         is_trial: true,
         is_trial: true,
+        subscriptionId: this.eventData.subscription.uuid,
       }
       }
     )
     )
     sinon.assert.calledWith(
     sinon.assert.calledWith(
@@ -199,6 +204,7 @@ describe('RecurlyEventHandler', function () {
         plan_code: this.planCode,
         plan_code: this.planCode,
         quantity: 1,
         quantity: 1,
         is_trial: true,
         is_trial: true,
+        subscriptionId: this.eventData.subscription.uuid,
       }
       }
     )
     )
     sinon.assert.calledWith(
     sinon.assert.calledWith(
@@ -234,6 +240,7 @@ describe('RecurlyEventHandler', function () {
         plan_code: this.planCode,
         plan_code: this.planCode,
         quantity: 1,
         quantity: 1,
         is_trial: true,
         is_trial: true,
+        subscriptionId: this.eventData.subscription.uuid,
       }
       }
     )
     )
   })
   })
@@ -250,27 +257,47 @@ describe('RecurlyEventHandler', function () {
       {
       {
         plan_code: this.planCode,
         plan_code: this.planCode,
         quantity: 1,
         quantity: 1,
+        subscriptionId: this.eventData.subscription.uuid,
       }
       }
     )
     )
   })
   })
 
 
   it('with paid_charge_invoice_notification', function () {
   it('with paid_charge_invoice_notification', function () {
+    const invoice = {
+      invoice_number: 1234,
+      currency: 'USD',
+      state: 'paid',
+      total_in_cents: 720,
+      tax_in_cents: 12,
+      address: {
+        country: 'Liurnia',
+      },
+      collection_method: 'automatic',
+      subscription_ids: ['abcd1234', 'defa3214'],
+    }
     this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
     this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
       'paid_charge_invoice_notification',
       'paid_charge_invoice_notification',
       {
       {
         account: {
         account: {
           account_code: this.userId,
           account_code: this.userId,
         },
         },
-        invoice: {
-          state: 'paid',
-          total_in_cents: 720,
-        },
+        invoice,
       }
       }
     )
     )
     sinon.assert.calledWith(
     sinon.assert.calledWith(
       this.AnalyticsManager.recordEventForUser,
       this.AnalyticsManager.recordEventForUser,
       this.userId,
       this.userId,
-      'subscription-invoice-collected'
+      'subscription-invoice-collected',
+      {
+        invoiceNumber: invoice.invoice_number,
+        currency: invoice.currency,
+        totalInCents: invoice.total_in_cents,
+        taxInCents: invoice.tax_in_cents,
+        country: invoice.address.country,
+        collectionMethod: invoice.collection_method,
+        subscriptionId1: invoice.subscription_ids[0],
+        subscriptionId2: invoice.subscription_ids[1],
+      }
     )
     )
   })
   })