Skip to content

Commit

Permalink
Merge pull request #14380 from mozilla/train-244-uplift-1
Browse files Browse the repository at this point in the history
Train 244 uplift 1
  • Loading branch information
dschom authored Oct 31, 2022
2 parents 99ff971 + 3e8d99d commit f848b4a
Show file tree
Hide file tree
Showing 33 changed files with 810 additions and 286 deletions.
6 changes: 6 additions & 0 deletions packages/fxa-auth-server/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,12 @@ const conf = convict({
env: 'AMPLITUDE_SCHEMA_VALIDATION',
format: Boolean,
},
rawEvents: {
default: false,
doc: 'Log raw Amplitude events',
env: 'AMPLITUDE_RAW_EVENTS',
format: Boolean,
},
},
memcached: {
address: {
Expand Down
62 changes: 50 additions & 12 deletions packages/fxa-auth-server/lib/metrics/amplitude.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ const { StatsD } = require('hot-shots');

const { GROUPS, initialize } = require('fxa-shared/metrics/amplitude');
const { version: VERSION } = require('../../package.json');
const { filterDntValues } = require('fxa-shared/metrics/dnt');

// Maps template name to email type
const EMAIL_TYPES = {
Expand Down Expand Up @@ -257,6 +256,56 @@ module.exports = (log, config) => {
time: metricsContext.time || Date.now(),
};

if (config.amplitude.rawEvents) {
const wanted = [
'entrypoint_experiment',
'entrypoint_variation',
'entrypoint',
'experiments',
'location',
'newsletters',
'syncEngines',
'templateVersion',
'userPreferences',
'utm_campaign',
'utm_content',
'utm_medium',
'utm_source',
'utm_term',
];
const picked = wanted.reduce((acc, v) => {
if (data[v] !== undefined) {
acc[v] = data[v];
}
return acc;
}, {});
const { location } = request.app.geo;
const rawEvent = {
event,
context: {
...picked,
eventSource: 'auth',
version: VERSION,
deviceId,
devices,
emailDomain: data.email_domain,
emailTypes: EMAIL_TYPES,
flowBeginTime,
flowId,
formFactor,
lang: request.app.locale,
location,
planId,
productId,
service,
uid,
userAgent: request.headers?.['user-agent'],
},
};
log.info('rawAmplitudeData', rawEvent);
statsd.increment('amplitude.event.raw');
}

statsd.increment('amplitude.event');

const amplitudeEvent = transformEvent(event, {
Expand All @@ -280,17 +329,6 @@ module.exports = (log, config) => {
});

if (amplitudeEvent) {
const dnt = request && request.headers && request.headers.dnt === '1';

if (dnt) {
amplitudeEvent.event_properties = filterDntValues(
amplitudeEvent.event_properties
);
amplitudeEvent.user_properties = filterDntValues(
amplitudeEvent.user_properties
);
}

log.amplitudeEvent(amplitudeEvent);

// HACK: Account reset returns a session token so emit login complete too
Expand Down
28 changes: 13 additions & 15 deletions packages/fxa-auth-server/lib/metrics/context.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

const bufferEqualConstantTime = require('buffer-equal-constant-time');
const crypto = require('crypto');
const { filterDntValues } = require('fxa-shared/metrics/dnt');
const HEX_STRING = require('../routes/validators').HEX_STRING;
const isA = require('joi');

Expand Down Expand Up @@ -163,25 +162,24 @@ module.exports = function (log, config) {
data.flowBeginTime = metadata.flowBeginTime;
data.flowCompleteSignal = metadata.flowCompleteSignal;
data.flowType = metadata.flowType;
data.entrypoint = metadata.entrypoint;
data.entrypoint_experiment = metadata.entrypointExperiment;
data.entrypoint_variation = metadata.entrypointVariation;
data.utm_campaign = metadata.utmCampaign;
data.utm_content = metadata.utmContent;
data.utm_medium = metadata.utmMedium;
data.utm_source = metadata.utmSource;
data.utm_term = metadata.utmTerm;
data.product_id = metadata.productId;
data.plan_id = metadata.planId;

if (metadata.service) {
data.service = metadata.service;
}
}

const doNotTrack = this.headers && this.headers.dnt === '1';
if (doNotTrack) {
data = filterDntValues(data);
const doNotTrack = this.headers && this.headers.dnt === '1';
if (!doNotTrack) {
data.entrypoint = metadata.entrypoint;
data.entrypoint_experiment = metadata.entrypointExperiment;
data.entrypoint_variation = metadata.entrypointVariation;
data.utm_campaign = metadata.utmCampaign;
data.utm_content = metadata.utmContent;
data.utm_medium = metadata.utmMedium;
data.utm_source = metadata.utmSource;
data.utm_term = metadata.utmTerm;
data.product_id = metadata.productId;
data.plan_id = metadata.planId;
}
}

return data;
Expand Down
56 changes: 51 additions & 5 deletions packages/fxa-auth-server/lib/payments/stripe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2809,6 +2809,33 @@ export class StripeHelper extends StripeHelperBase {

const productPaymentCycleNew = this.stripePlanToPaymentCycle(planNew);

// During upgrades it's possible that an invoice isn't created when the
// subscription is updated. Instead there will be pending invoice items
// which will be added to next invoice once its generated.
// For more info see https://stripe.com/docs/api/subscriptions/update
let upcomingInvoiceWithInvoiceitem: Stripe.Invoice | undefined;
try {
const upcomingInvoice = await this.stripe.invoices.retrieveUpcoming({
customer: customer.id,
subscription: subscription.id,
});
// Only use upcomingInvoice if there are `invoiceitems`
upcomingInvoiceWithInvoiceitem = upcomingInvoice?.lines.data.some(
(line) => line.type === 'invoiceitem'
)
? upcomingInvoice
: undefined;
} catch (error) {
if (
error.type === 'StripeInvalidRequestError' &&
error.code === 'invoice_upcoming_none'
) {
upcomingInvoiceWithInvoiceitem = undefined;
} else {
throw error;
}
}

const baseDetails = {
uid,
email,
Expand Down Expand Up @@ -2838,7 +2865,8 @@ export class StripeHelper extends StripeHelperBase {
return this.extractSubscriptionUpdateCancellationDetailsForEmail(
subscription,
baseDetails,
invoice
invoice,
upcomingInvoiceWithInvoiceitem
);
} else if (cancelAtPeriodEndOld && !cancelAtPeriodEndNew && !planOld) {
return this.extractSubscriptionUpdateReactivationDetailsForEmail(
Expand All @@ -2850,6 +2878,7 @@ export class StripeHelper extends StripeHelperBase {
subscription,
baseDetails,
invoice,
upcomingInvoiceWithInvoiceitem,
productOrderNew,
planOld
);
Expand All @@ -2866,7 +2895,8 @@ export class StripeHelper extends StripeHelperBase {
async extractSubscriptionUpdateCancellationDetailsForEmail(
subscription: Stripe.Subscription,
baseDetails: any,
invoice: Stripe.Invoice
invoice: Stripe.Invoice,
upcomingInvoiceWithInvoiceitem: Stripe.Invoice | undefined
) {
const { current_period_end: serviceLastActiveDate } = subscription;

Expand All @@ -2885,7 +2915,7 @@ export class StripeHelper extends StripeHelperBase {
total: invoiceTotalInCents,
currency: invoiceTotalCurrency,
created: invoiceDate,
} = invoice;
} = upcomingInvoiceWithInvoiceitem || invoice;

return {
updateType: SUBSCRIPTION_UPDATE_TYPES.CANCELLATION,
Expand All @@ -2899,6 +2929,7 @@ export class StripeHelper extends StripeHelperBase {
invoiceTotalInCents,
invoiceTotalCurrency,
serviceLastActiveDate: new Date(serviceLastActiveDate * 1000),
showOutstandingBalance: !!upcomingInvoiceWithInvoiceitem,
productMetadata,
planConfig,
};
Expand Down Expand Up @@ -3021,16 +3052,31 @@ export class StripeHelper extends StripeHelperBase {
subscription: Stripe.Subscription,
baseDetails: any,
invoice: Stripe.Invoice,
upcomingInvoiceWithInvoiceitem: Stripe.Invoice | undefined,
productOrderNew: string,
planOld: Stripe.Plan
) {
const {
id: invoiceId,
number: invoiceNumber,
currency: paymentProratedCurrency,
amount_due: paymentProratedInCents,
} = invoice;

// Using stripes default proration behaviour
// (https://stripe.com/docs/billing/subscriptions/upgrade-downgrade#immediate-payment)
// an invoice is only created at time of upgrade, if the billing period changes.
// In the case that the billing period is the same, we sum the pending invoiceItems
// retrieved in upcomingInvoiceWithInvoiceitem.
// The actual recuring charge, for the next billing cycle, shows up as a type = 'subscription'
// line item.
const onetimePaymentAmount = upcomingInvoiceWithInvoiceitem
? upcomingInvoiceWithInvoiceitem.lines.data.reduce(
(acc, line) =>
line.type === 'invoiceitem' ? acc + line.amount : acc,
0
)
: invoice.amount_due;

// https://github.com/mozilla/subhub/blob/e224feddcdcbafaf0f3cd7d52691d29d94157de5/src/hub/vendor/customer.py#L643
const abbrevProductOld = await this.expandAbbrevProductForPlan(planOld);
const {
Expand Down Expand Up @@ -3062,7 +3108,7 @@ export class StripeHelper extends StripeHelperBase {
paymentAmountOldCurrency,
invoiceNumber,
invoiceId,
paymentProratedInCents,
paymentProratedInCents: onetimePaymentAmount,
paymentProratedCurrency,
};
}
Expand Down
2 changes: 2 additions & 0 deletions packages/fxa-auth-server/lib/senders/email.js
Original file line number Diff line number Diff line change
Expand Up @@ -2096,6 +2096,7 @@ module.exports = function (log, config, bounces) {
invoiceTotalInCents,
invoiceTotalCurrency,
serviceLastActiveDate,
showOutstandingBalance,
} = message;

const enabled = config.subscriptions.transactionalEmails.enabled;
Expand Down Expand Up @@ -2142,6 +2143,7 @@ module.exports = function (log, config, bounces) {
invoiceTotalCurrency,
message.acceptLanguage
),
showOutstandingBalance,
},
});
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ subscriptionCancellation-title = Sorry to see you go
# $invoiceDateOnly (String) - The date of the invoice, e.g. 01/20/2016
# $serviceLastActiveDateOnly (String) - The date of last active service, e.g. 01/20/2016
subscriptionCancellation-content = We’ve cancelled your { $productName } subscription. Your final payment of { $invoiceTotal } was paid on { $invoiceDateOnly }. Your service will continue until the end of your current billing period, which is { $serviceLastActiveDateOnly }.
subscriptionCancellation-outstanding-content = We’ve cancelled your { $productName } subscription. Your final payment of { $invoiceTotal } will be paid on { $invoiceDateOnly }. Your service will continue until the end of your current billing period, which is { $serviceLastActiveDateOnly }.
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,15 @@
<mj-section>
<mj-column>
<mj-text css-class="text-body">
<span data-l10n-id="subscriptionCancellation-content" data-l10n-args="<%= JSON.stringify({productName, invoiceTotal, invoiceDateOnly, serviceLastActiveDateOnly}) %>">
<% if (!showOutstandingBalance) { %>
<span data-l10n-id="subscriptionCancellation-content" data-l10n-args="<%= JSON.stringify({productName, invoiceTotal, invoiceDateOnly, serviceLastActiveDateOnly}) %>">
We’ve cancelled your <%- productName %> subscription. Your final payment of <%- invoiceTotal %> was paid on <%- invoiceDateOnly %>. Your service will continue until the end of your current billing period, which is <%- serviceLastActiveDateOnly %>.
</span>
<% } else { %>
<span data-l10n-id="subscriptionCancellation-outstanding-content" data-l10n-args="<%= JSON.stringify({productName, invoiceTotal, invoiceDateOnly, serviceLastActiveDateOnly}) %>">
We’ve cancelled your <%- productName %> subscription. Your final payment of <%- invoiceTotal %> will be paid on <%- invoiceDateOnly %>. Your service will continue until the end of your current billing period, which is <%- serviceLastActiveDateOnly %>.
</span>
<% } %>
</mj-text>
</mj-column>
</mj-section>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ subscriptionCancellation-subject = "Your <%- productName %> subscription has bee

subscriptionCancellation-title = "Sorry to see you go"

<% if (!showOutstandingBalance) { %>
subscriptionCancellation-content = "We’ve cancelled your <%- productName %> subscription. Your final payment of <%- invoiceTotal %> was paid on <%- invoiceDateOnly %>. Your service will continue until the end of your current billing period, which is <%- serviceLastActiveDateOnly %>."
<% } else { %>
subscriptionCancellation-outstanding-content = "We’ve cancelled your <%- productName %> subscription. Your final payment of <%- invoiceTotal %> will be paid on <%- invoiceDateOnly %>. Your service will continue until the end of your current billing period, which is <%- serviceLastActiveDateOnly %>."
<% } %>

<%- include ('/partials/cancellationSurvey/index.txt') %>
Loading

0 comments on commit f848b4a

Please sign in to comment.