Skip to content

Commit bdb9e34

Browse files
Merge pull request #20182 from mozilla/PAY-3548-add-subscription-cancellation-email-variant-with-free-trial-language
feat(payments-next): Add SubscriptionCancellation email variant with free trial language
2 parents a2cc023 + 13af63d commit bdb9e34

19 files changed

Lines changed: 314 additions & 18 deletions

File tree

libs/accounts/email-renderer/src/renderer/subplat-email-renderer.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,11 +96,21 @@ export class SubplatEmailRender extends EmailRenderer {
9696
templateValues: SubscriptionCancellation.TemplateData,
9797
layoutTemplateValues: SubscriptionLayouts.TemplateData
9898
) {
99+
const includes = templateValues.isFreeTrialCancellation
100+
? {
101+
...SubscriptionCancellation.includes,
102+
subject: {
103+
id: 'subscriptionCancellation-freeTrial-subject',
104+
message: 'Your <%- productName %> free trial has been canceled',
105+
},
106+
}
107+
: SubscriptionCancellation.includes;
108+
99109
return this.renderEmail({
100110
template: SubscriptionCancellation.template,
101111
version: SubscriptionCancellation.version,
102112
layout: SubscriptionCancellation.layout,
103-
includes: SubscriptionCancellation.includes,
113+
includes,
104114
...templateValues,
105115
...layoutTemplateValues,
106116
});

libs/accounts/email-renderer/src/templates/subscriptionCancellation/en.ftl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,12 @@ subscriptionCancellation-outstanding-content-2 = We’ve canceled your { $produc
1414
# Variables
1515
# $serviceLastActiveDateOnly (String) - The date of last active service, e.g. 01/20/2016
1616
subscriptionCancellation-content-continue = Your service will continue until the end of your current billing period, which is { $serviceLastActiveDateOnly }.
17+
18+
# Variables
19+
# $productName (String) - The name of the subscribed product, e.g. Mozilla VPN
20+
subscriptionCancellation-freeTrial-subject = Your { $productName } free trial has been canceled
21+
22+
# Variables
23+
# $productName (String) - The name of the subscribed product, e.g. Mozilla VPN
24+
# $trialEndDateOnly (String) - The date when the free trial ends, e.g. 01/20/2016
25+
subscriptionCancellation-freeTrial-content = Your free trial of { $productName } has been canceled. Your access will end on { $trialEndDateOnly }. You will not be charged.

libs/accounts/email-renderer/src/templates/subscriptionCancellation/index.mjml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@
1313
<mj-section>
1414
<mj-column>
1515
<mj-text css-class="text-body">
16-
<% if (!showOutstandingBalance) { %>
16+
<% if (isFreeTrialCancellation) { %>
17+
<span data-l10n-id="subscriptionCancellation-freeTrial-content" data-l10n-args="<%= JSON.stringify({productName, trialEndDateOnly}) %>">
18+
Your free trial of <%- productName %> has been canceled. Your access will end on <%- trialEndDateOnly %>. You will not be charged.
19+
</span>
20+
<% } else if (!showOutstandingBalance) { %>
1721
<span data-l10n-id="subscriptionCancellation-content-2" data-l10n-args="<%= JSON.stringify({productName, invoiceTotal, invoiceDateOnly, serviceLastActiveDateOnly}) %>">
1822
We’ve cancelled your <%- productName %> subscription. Your final payment of <%- invoiceTotal %> was paid on <%- invoiceDateOnly %>.
1923
</span>
@@ -22,7 +26,7 @@
2226
We’ve cancelled your <%- productName %> subscription. Your final payment of <%- invoiceTotal %> will be paid on <%- invoiceDateOnly %>.
2327
</span>
2428
<% } %>
25-
<% if (cancelAtEnd) { %>
29+
<% if (!isFreeTrialCancellation && cancelAtEnd) { %>
2630
<span data-l10n-id="subscriptionCancellation-content-continue" data-l10n-args="<%= JSON.stringify({serviceLastActiveDateOnly}) %>">
2731
Your service will continue until the end of your current billing period, which is <%- serviceLastActiveDateOnly %>.
2832
</span>

libs/accounts/email-renderer/src/templates/subscriptionCancellation/index.stories.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ const data = {
2020
'https://survey.alchemer.com/s3/6534408/Privacy-Security-Product-Cancellation-of-Service-Q4-21',
2121
showOutstandingBalance: true,
2222
cancelAtEnd: false,
23+
isFreeTrialCancellation: false,
2324
};
2425

2526
const createStory = subplatStoryWithProps<TemplateData>(
@@ -30,3 +31,27 @@ const createStory = subplatStoryWithProps<TemplateData>(
3031
);
3132

3233
export const SubscriptionCancellation = createStory();
34+
35+
const freeTrialData = {
36+
...data,
37+
isFreeTrialCancellation: true,
38+
showOutstandingBalance: false,
39+
trialEndDateOnly: '12/13/2021',
40+
};
41+
42+
const freeTrialIncludes = {
43+
...includes,
44+
subject: {
45+
id: 'subscriptionCancellation-freeTrial-subject',
46+
message: 'Your <%- productName %> free trial has been canceled',
47+
},
48+
};
49+
50+
const createFreeTrialStory = subplatStoryWithProps<TemplateData>(
51+
'subscriptionCancellation',
52+
'Sent when a user cancels their free trial.',
53+
freeTrialData,
54+
freeTrialIncludes
55+
);
56+
57+
export const FreeTrialCancellation = createFreeTrialStory();

libs/accounts/email-renderer/src/templates/subscriptionCancellation/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@ export type TemplateData = CancellationSurveyTemplateData & {
1313
cancellationSurveryUrl?: string;
1414
showOutstandingBalance: boolean;
1515
cancelAtEnd: boolean;
16+
isFreeTrialCancellation: boolean;
17+
trialEndDateOnly?: string;
1618
};
1719

1820
export const template = 'subscriptionCancellation';
19-
export const version = 3;
21+
export const version = 4;
2022
export const layout = 'subscription';
2123
export const includes = {
2224
subject: {

libs/accounts/email-renderer/src/templates/subscriptionCancellation/index.txt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
1+
<% if (isFreeTrialCancellation) { %>
2+
subscriptionCancellation-freeTrial-subject = "Your <%- productName %> free trial has been cancelled"
3+
<% } else { %>
14
subscriptionCancellation-subject = "Your <%- productName %> subscription has been cancelled"
5+
<% } %>
26

37
subscriptionCancellation-title = "Sorry to see you go"
48

5-
<% if (!showOutstandingBalance) { %>
9+
<% if (isFreeTrialCancellation) { %>
10+
subscriptionCancellation-freeTrial-content = "Your free trial of <%- productName %> has been cancelled. Your access will end on <%- trialEndDateOnly %>. You will not be charged."
11+
<% } else if (!showOutstandingBalance) { %>
612
subscriptionCancellation-content-2 = "We’ve cancelled your <%- productName %> subscription. Your final payment of <%- invoiceTotal %> was paid on <%- invoiceDateOnly %>."
713
<% } else { %>
814
subscriptionCancellation-outstanding-content-2 = "We’ve cancelled your <%- productName %> subscription. Your final payment of <%- invoiceTotal %> will be paid on <%- invoiceDateOnly %>."
915
<% } %>
10-
<% if (cancelAtEnd) { %>
16+
<% if (!isFreeTrialCancellation && cancelAtEnd) { %>
1117
subscriptionCancellation-content-continue = "Your service will continue until the end of your current billing period, which is <%- serviceLastActiveDateOnly %>."
1218
<% } %>
1319

packages/fxa-auth-server/lib/payments/stripe.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3301,6 +3301,13 @@ export class StripeHelper extends StripeHelperBase {
33013301
created: invoiceDate,
33023302
} = upcomingInvoiceWithInvoiceItem || invoice;
33033303

3304+
const isFreeTrialCancellation =
3305+
subscription.trial_start != null &&
3306+
subscription.trial_end != null &&
3307+
subscription.canceled_at != null &&
3308+
subscription.canceled_at >= subscription.trial_start &&
3309+
subscription.canceled_at <= subscription.trial_end;
3310+
33043311
return {
33053312
updateType: SUBSCRIPTION_UPDATE_TYPES.CANCELLATION,
33063313
email,
@@ -3314,6 +3321,10 @@ export class StripeHelper extends StripeHelperBase {
33143321
invoiceTotalCurrency,
33153322
serviceLastActiveDate: new Date(serviceLastActiveDate * 1000),
33163323
showOutstandingBalance: !!upcomingInvoiceWithInvoiceItem,
3324+
isFreeTrialCancellation,
3325+
...(isFreeTrialCancellation && subscription.trial_end
3326+
? { trialEnd: new Date(subscription.trial_end * 1000) }
3327+
: {}),
33173328
productMetadata,
33183329
planConfig,
33193330
};

packages/fxa-auth-server/lib/routes/subscriptions/stripe-webhook.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1095,6 +1095,13 @@ export class StripeWebhookHandler extends StripeHandler {
10951095
// If invoice is open or draft, assume there is an oustanding balance
10961096
const showOutstandingBalance =
10971097
invoiceStatus && ['open', 'draft'].includes(invoiceStatus);
1098+
const isFreeTrialCancellation =
1099+
subscription.trial_start != null &&
1100+
subscription.trial_end != null &&
1101+
subscription.canceled_at != null &&
1102+
subscription.canceled_at >= subscription.trial_start &&
1103+
subscription.canceled_at <= subscription.trial_end;
1104+
10981105
await this.mailer.sendSubscriptionCancellationEmail(
10991106
account.emails,
11001107
account,
@@ -1103,6 +1110,10 @@ export class StripeWebhookHandler extends StripeHandler {
11031110
...invoiceDetails,
11041111
showOutstandingBalance,
11051112
cancelAtEnd: subscription.cancel_at_period_end,
1113+
isFreeTrialCancellation,
1114+
...(isFreeTrialCancellation && subscription.trial_end
1115+
? { trialEnd: new Date(subscription.trial_end * 1000) }
1116+
: {}),
11061117
email: account.primaryEmail,
11071118
}
11081119
);

packages/fxa-auth-server/lib/senders/email.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2945,6 +2945,8 @@ module.exports = function (log, config, bounces, statsd) {
29452945
serviceLastActiveDate,
29462946
showOutstandingBalance,
29472947
cancelAtEnd = true,
2948+
isFreeTrialCancellation = false,
2949+
trialEnd,
29482950
} = message;
29492951

29502952
const enabled = config.subscriptions.transactionalEmails.enabled;
@@ -2999,6 +3001,16 @@ module.exports = function (log, config, bounces, statsd) {
29993001
),
30003002
showOutstandingBalance,
30013003
cancelAtEnd,
3004+
isFreeTrialCancellation,
3005+
...(trialEnd
3006+
? {
3007+
trialEndDateOnly: this._constructLocalDateString(
3008+
message.timeZone,
3009+
message.acceptLanguage,
3010+
trialEnd
3011+
),
3012+
}
3013+
: {}),
30023014
},
30033015
});
30043016
};

packages/fxa-auth-server/lib/senders/emails/templates/_versions.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"subscriptionsPaymentProviderCancelled": 3,
1111
"subscriptionPaymentFailed": 3,
1212
"subscriptionAccountDeletion": 2,
13-
"subscriptionCancellation": 3,
13+
"subscriptionCancellation": 4,
1414
"subscriptionFailedPaymentsCancellation": 2,
1515
"subscriptionReplaced": 1,
1616
"subscriptionSubsequentInvoice": 5,

0 commit comments

Comments
 (0)