Skip to content

Commit 056213d

Browse files
Merge pull request #19961 from mozilla/PAY-3485-update-subscription-reminder-emails-on-discount-change
Update subscription reminder emails on discount change
2 parents 35c7a99 + 99c12c0 commit 056213d

14 files changed

Lines changed: 759 additions & 15 deletions

File tree

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ subscriptionRenewalReminder-content-greeting = Dear { $productName } customer,
88
# Variables
99
# $reminderLength (String) - The number of days until the current subscription is set to automatically renew, e.g. 14
1010
subscriptionRenewalReminder-content-intro = Your current subscription is set to automatically renew in { $reminderLength } days.
11+
subscriptionRenewalReminder-content-discount-change = Your next invoice reflects a change in pricing, as a previous discount has ended and a new discount has been applied.
1112
subscriptionRenewalReminder-content-discount-ending = Because a previous discount has ended, your subscription will renew at the standard price.
1213
# Variables
1314
# $invoiceTotal (String) - The amount of the subscription invoice, including currency, e.g. $10.00

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@
2424
Because a previous discount has ended, your subscription will renew at the standard price.
2525
</span>
2626
</mj-text>
27+
<% } else if (locals.hasDifferentDiscount) { %>
28+
<mj-text css-class="text-body">
29+
<span data-l10n-id="subscriptionRenewalReminder-content-discount-change">
30+
Your next invoice reflects a change in pricing, as a previous discount has ended and a new discount has been applied.
31+
</span>
32+
</mj-text>
2733
<% } %>
2834
2935
<mj-text css-class="text-body">

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ const data = {
1919
subscriptionSupportUrl: 'http://localhost:3030/support',
2020
updateBillingUrl: 'http://localhost:3030/subscriptions',
2121
hadDiscount: false,
22+
hasDifferentDiscount: false,
2223
};
2324

2425
const createStory = subplatStoryWithProps<TemplateData>(
@@ -58,6 +59,28 @@ export const YearlyPlanDiscountEnding = createStory(
5859
reminderLength: '15',
5960
invoiceTotal: '$199.99',
6061
hadDiscount: true,
62+
hasDifferentDiscount: false,
6163
},
6264
'Yearly Plan - Discount Ending'
6365
);
66+
67+
export const MonthlyPlanDiscountChanging = createStory(
68+
{
69+
hadDiscount: true,
70+
hasDifferentDiscount: true,
71+
invoiceTotal: '$14.00',
72+
},
73+
'Monthly Plan - Discount Changing'
74+
);
75+
76+
export const YearlyPlanDiscountChanging = createStory(
77+
{
78+
planInterval: 'year',
79+
planIntervalCount: '1',
80+
reminderLength: '15',
81+
invoiceTotal: '$139.99',
82+
hadDiscount: true,
83+
hasDifferentDiscount: true,
84+
},
85+
'Yearly Plan - Discount Changing'
86+
);

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,11 @@ export type TemplateData = SubscriptionSupportContactTemplateData &
1515
subscriptionSupportUrl: string;
1616
updateBillingUrl: string;
1717
hadDiscount?: boolean;
18+
hasDifferentDiscount?: boolean;
1819
};
1920

2021
export const template = 'subscriptionRenewalReminder';
21-
export const version = 3;
22+
export const version = 4;
2223
export const layout = 'subscription';
2324
export const includes = {
2425
subject: {

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ subscriptionRenewalReminder-content-intro = "Your current subscription is set to
88

99
<% if (locals.hadDiscount) { %>
1010
subscriptionRenewalReminder-content-discount-ending = "Because a previous discount has ended, your subscription will renew at the standard price."
11+
<% } else if (locals.hasDifferentDiscount) { %>
12+
subscriptionRenewalReminder-content-discount-change = "Your next invoice reflects a change in pricing, as a previous discount has ended and a new discount has been applied."
13+
<% } %>
1114

1215
subscriptionRenewalReminder-content-charge = "At that time, Mozilla will renew your <%- planIntervalCount %> <%- planInterval %> subscription and a charge of <%- invoiceTotal %> will be applied to the payment method on your account."
13-
<% } else { %>
14-
subscriptionRenewalReminder-content-charge = "At that time, Mozilla will renew your <%- planIntervalCount %> <%- planInterval %> subscription and a charge of <%- invoiceTotal %> will be applied to the payment method on your account."
15-
<% } %>
1616

1717
<%- include ('/partials/subscriptionUpdateBillingEnsure/index.txt') %>
1818

packages/fxa-auth-server/lib/payments/subscription-reminders.ts

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -266,15 +266,25 @@ export class SubscriptionReminders {
266266
}
267267

268268
/**
269-
* Determine if a discount is ending by checking that the subscription currently
270-
* has a discount but the upcoming invoice does not.
271-
* TODO in PAY-3485: Handle the case where the discount changes without ending.
269+
* Determine if a discount is ending by checking that a discount currently exists
270+
* but will not be present on the upcoming invoice does not.
272271
*/
273272
private hasDiscountEnding(
274-
subscription: Stripe.Subscription,
275-
invoicePreview: Stripe.UpcomingInvoice
273+
currentDiscountId: string | null,
274+
upcomingDiscountId: string | null,
276275
): boolean {
277-
return !!subscription.discount && !invoicePreview.discount;
276+
return !!currentDiscountId && !upcomingDiscountId;
277+
}
278+
279+
/**
280+
* Determine if the upcoming invoice has a discount that is different from
281+
* the current discount.
282+
*/
283+
private hasDifferentDiscount(
284+
currentDiscountId: string | null,
285+
upcomingDiscountId: string | null,
286+
): boolean {
287+
return !!currentDiscountId && !!upcomingDiscountId && currentDiscountId !== upcomingDiscountId;
278288
}
279289

280290
/**
@@ -339,8 +349,28 @@ export class SubscriptionReminders {
339349
subscriptionId: subscription.id,
340350
});
341351

352+
// Check latest invoice for current discount
353+
let latestInvoice = subscription.latest_invoice;
354+
if (typeof latestInvoice === 'string') {
355+
latestInvoice = await this.stripeHelper.getInvoice(latestInvoice);
356+
}
357+
const currentDiscount = latestInvoice?.discount || latestInvoice?.discounts?.[0];
358+
const currentDiscountId = typeof currentDiscount === 'string'
359+
? currentDiscount
360+
: currentDiscount?.id ?? null;
361+
362+
// Check upcoming invoice for upcoming discount
363+
const upcomingDiscount = invoicePreview.discount || invoicePreview.discounts?.[0];
364+
const upcomingDiscountId = upcomingDiscount
365+
? typeof upcomingDiscount === 'string'
366+
? upcomingDiscount
367+
: upcomingDiscount.id
368+
: null;
369+
342370
// Detect if discount is ending
343-
const hadDiscount = this.hasDiscountEnding(subscription, invoicePreview);
371+
const hadDiscount = this.hasDiscountEnding(currentDiscountId, upcomingDiscountId);
372+
// Detect if renewal has a different discount
373+
const hasDifferentDiscount = this.hasDifferentDiscount(currentDiscountId, upcomingDiscountId);
344374

345375
await this.mailer.sendSubscriptionRenewalReminderEmail(
346376
account.emails,
@@ -359,6 +389,7 @@ export class SubscriptionReminders {
359389
productMetadata: formattedSubscription.productMetadata,
360390
planConfig: formattedSubscription.planConfig,
361391
hadDiscount,
392+
hasDifferentDiscount,
362393
}
363394
);
364395
await this.updateSentEmail(

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3253,6 +3253,7 @@ module.exports = function (log, config, bounces, statsd) {
32533253
message.acceptLanguage
32543254
),
32553255
hadDiscount: message.hadDiscount || false,
3256+
hasDifferentDiscount: message.hasDifferentDiscount || false,
32563257
},
32573258
});
32583259
};

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"subscriptionReactivation": 2,
3-
"subscriptionRenewalReminder": 3,
3+
"subscriptionRenewalReminder": 4,
44
"subscriptionEndingReminder": 1,
55
"subscriptionUpgrade": 7,
66
"subscriptionDowngrade": 2,

packages/fxa-auth-server/lib/senders/emails/templates/subscriptionRenewalReminder/en.ftl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ subscriptionRenewalReminder-content-greeting = Dear { $productName } customer,
88
# Variables
99
# $reminderLength (String) - The number of days until the current subscription is set to automatically renew, e.g. 14
1010
subscriptionRenewalReminder-content-intro = Your current subscription is set to automatically renew in { $reminderLength } days.
11+
subscriptionRenewalReminder-content-discount-change = Your next invoice reflects a change in pricing, as a previous discount has ended and a new discount has been applied.
1112
subscriptionRenewalReminder-content-discount-ending = Because a previous discount has ended, your subscription will renew at the standard price.
1213
# Variables
1314
# $invoiceTotal (String) - The amount of the subscription invoice, including currency, e.g. $10.00

packages/fxa-auth-server/lib/senders/emails/templates/subscriptionRenewalReminder/index.mjml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@
2424
Because a previous discount has ended, your subscription will renew at the standard price.
2525
</span>
2626
</mj-text>
27+
<% } else if (hasDifferentDiscount) { %>
28+
<mj-text css-class="text-body">
29+
<span data-l10n-id="subscriptionRenewalReminder-content-discount-change">
30+
Your next invoice reflects a change in pricing, as a previous discount has ended and a new discount has been applied.
31+
</span>
32+
</mj-text>
2733
<% } %>
2834
2935
<mj-text css-class="text-body">

0 commit comments

Comments
 (0)