Skip to content

Commit eda3ead

Browse files
Merge pull request #20005 from mozilla/PAY-2291
feat(payments-next): Update email reminder logic
2 parents dc37c53 + 8699485 commit eda3ead

12 files changed

Lines changed: 194 additions & 65 deletions

File tree

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
</span>
1919
</mj-text>
2020

21-
<% if (locals.hadDiscount) { %>
21+
<% if (locals.discountEnding) { %>
2222
<mj-text css-class="text-body">
2323
<span data-l10n-id="subscriptionRenewalReminder-content-discount-ending">
2424
Because a previous discount has ended, your subscription will renew at the standard price.

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ const data = {
1818
reminderLength: '7',
1919
subscriptionSupportUrl: 'http://localhost:3030/support',
2020
updateBillingUrl: 'http://localhost:3030/subscriptions',
21-
hadDiscount: false,
21+
discountEnding: false,
2222
hasDifferentDiscount: false,
2323
};
2424

@@ -36,7 +36,7 @@ export const MonthlyPlanNoDiscount = createStory(
3636

3737
export const MonthlyPlanDiscountEnding = createStory(
3838
{
39-
hadDiscount: true,
39+
discountEnding: true,
4040
},
4141
'Monthly Plan - Discount Ending'
4242
);
@@ -47,7 +47,7 @@ export const YearlyPlanNoDiscount = createStory(
4747
planIntervalCount: '1',
4848
reminderLength: '15',
4949
invoiceTotal: '$199.99',
50-
hadDiscount: false,
50+
discountEnding: false,
5151
},
5252
'Yearly Plan - No Discount'
5353
);
@@ -58,15 +58,15 @@ export const YearlyPlanDiscountEnding = createStory(
5858
planIntervalCount: '1',
5959
reminderLength: '15',
6060
invoiceTotal: '$199.99',
61-
hadDiscount: true,
61+
discountEnding: true,
6262
hasDifferentDiscount: false,
6363
},
6464
'Yearly Plan - Discount Ending'
6565
);
6666

6767
export const MonthlyPlanDiscountChanging = createStory(
6868
{
69-
hadDiscount: true,
69+
discountEnding: true,
7070
hasDifferentDiscount: true,
7171
invoiceTotal: '$14.00',
7272
},
@@ -79,7 +79,7 @@ export const YearlyPlanDiscountChanging = createStory(
7979
planIntervalCount: '1',
8080
reminderLength: '15',
8181
invoiceTotal: '$139.99',
82-
hadDiscount: true,
82+
discountEnding: true,
8383
hasDifferentDiscount: true,
8484
},
8585
'Yearly Plan - Discount Changing'

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export type TemplateData = SubscriptionSupportContactTemplateData &
1414
reminderLength: string;
1515
subscriptionSupportUrl: string;
1616
updateBillingUrl: string;
17-
hadDiscount?: boolean;
17+
discountEnding?: boolean;
1818
hasDifferentDiscount?: boolean;
1919
};
2020

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ subscriptionRenewalReminder-content-greeting = "Dear <%- productName %> customer
66

77
subscriptionRenewalReminder-content-intro = "Your current subscription is set to automatically renew in <%- reminderLength %> days."
88

9-
<% if (locals.hadDiscount) { %>
9+
<% if (locals.discountEnding) { %>
1010
subscriptionRenewalReminder-content-discount-ending = "Because a previous discount has ended, your subscription will renew at the standard price."
1111
<% } else if (locals.hasDifferentDiscount) { %>
1212
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."

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

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -331,14 +331,6 @@ export class SubscriptionReminders {
331331
}
332332
try {
333333
const account = await this.db.account(uid);
334-
this.log.info('sendSubscriptionRenewalReminderEmail', {
335-
message: 'Sending a renewal reminder email.',
336-
subscriptionId: subscription.id,
337-
currentPeriodStart: subscription.current_period_start,
338-
currentPeriodEnd: subscription.current_period_end,
339-
currentDateMs: Date.now(),
340-
reminderLength: effectiveReminderDuration.as('days'),
341-
});
342334
const { email } = account;
343335
const formattedSubscription =
344336
await this.stripeHelper.formatSubscriptionForEmail(subscription);
@@ -368,10 +360,30 @@ export class SubscriptionReminders {
368360
: null;
369361

370362
// Detect if discount is ending
371-
const hadDiscount = this.hasDiscountEnding(currentDiscountId, upcomingDiscountId);
363+
const discountEnding = this.hasDiscountEnding(currentDiscountId, upcomingDiscountId);
372364
// Detect if renewal has a different discount
373365
const hasDifferentDiscount = this.hasDifferentDiscount(currentDiscountId, upcomingDiscountId);
374366

367+
// Business rule: Monthly subscriptions only receive renewal reminders when a discount is ending,
368+
// to avoid notification fatigue for standard monthly renewals.
369+
if (interval === 'month' && !discountEnding) {
370+
this.log.info('sendSubscriptionRenewalReminderEmail.skippingMonthlyNoDiscount', {
371+
subscriptionId: subscription.id,
372+
planId,
373+
});
374+
return false;
375+
}
376+
377+
// If we reach here, we're sending the email
378+
this.log.info('sendSubscriptionRenewalReminderEmail', {
379+
message: 'Sending a renewal reminder email.',
380+
subscriptionId: subscription.id,
381+
currentPeriodStart: subscription.current_period_start,
382+
currentPeriodEnd: subscription.current_period_end,
383+
currentDateMs: Date.now(),
384+
reminderLength: effectiveReminderDuration.as('days'),
385+
});
386+
375387
await this.mailer.sendSubscriptionRenewalReminderEmail(
376388
account.emails,
377389
account,
@@ -388,7 +400,7 @@ export class SubscriptionReminders {
388400
invoiceTotalCurrency: invoicePreview.currency,
389401
productMetadata: formattedSubscription.productMetadata,
390402
planConfig: formattedSubscription.planConfig,
391-
hadDiscount,
403+
discountEnding,
392404
hasDifferentDiscount,
393405
}
394406
);
@@ -488,8 +500,8 @@ export class SubscriptionReminders {
488500
* Sends a reminder email for all active subscriptions for all plans
489501
* as long or longer than `planLength`:
490502
* 1. Get a list of all plans of sufficient `planLength`
491-
* 2. Send 30-day reminders for yearly plans (if enabled)
492-
* 3. Send 14-day reminders for all plans
503+
* 2. Send 15-day reminders for yearly plans (if enabled)
504+
* 3. Send 7-day reminders for monthly plans
493505
* 4. If enabled, send subscription ending reminder emails if one
494506
* hasn't already been sent.
495507
*/

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3252,7 +3252,7 @@ module.exports = function (log, config, bounces, statsd) {
32523252
message.invoiceTotalCurrency,
32533253
message.acceptLanguage
32543254
),
3255-
hadDiscount: message.hadDiscount || false,
3255+
discountEnding: message.discountEnding || false,
32563256
hasDifferentDiscount: message.hasDifferentDiscount || false,
32573257
},
32583258
});

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
</span>
1919
</mj-text>
2020

21-
<% if (hadDiscount) { %>
21+
<% if (discountEnding) { %>
2222
<mj-text css-class="text-body">
2323
<span data-l10n-id="subscriptionRenewalReminder-content-discount-ending">
2424
Because a previous discount has ended, your subscription will renew at the standard price.

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const createStory = subplatStoryWithProps(
2020
reminderLength: '7',
2121
subscriptionSupportUrl: 'http://localhost:3030/support',
2222
updateBillingUrl: 'http://localhost:3030/subscriptions',
23-
hadDiscount: false,
23+
discountEnding: false,
2424
hasDifferentDiscount: false,
2525
}
2626
);
@@ -32,7 +32,7 @@ export const MonthlyPlanNoDiscount = createStory(
3232

3333
export const MonthlyPlanDiscountEnding = createStory(
3434
{
35-
hadDiscount: true,
35+
discountEnding: true,
3636
},
3737
'Monthly Plan - Discount Ending'
3838
);
@@ -43,7 +43,7 @@ export const YearlyPlanNoDiscount = createStory(
4343
planIntervalCount: '1',
4444
reminderLength: '15',
4545
invoiceTotal: '$199.99',
46-
hadDiscount: false,
46+
discountEnding: false,
4747
},
4848
'Yearly Plan - No Discount'
4949
);
@@ -54,15 +54,15 @@ export const YearlyPlanDiscountEnding = createStory(
5454
planIntervalCount: '1',
5555
reminderLength: '15',
5656
invoiceTotal: '$199.99',
57-
hadDiscount: true,
57+
discountEnding: true,
5858
hasDifferentDiscount: false,
5959
},
6060
'Yearly Plan - Discount Ending'
6161
);
6262

6363
export const MonthlyPlanDiscountChanging = createStory(
6464
{
65-
hadDiscount: true,
65+
discountEnding: true,
6666
hasDifferentDiscount: true,
6767
invoiceTotal: '$14.00',
6868
},
@@ -75,7 +75,7 @@ export const YearlyPlanDiscountChanging = createStory(
7575
planIntervalCount: '1',
7676
reminderLength: '15',
7777
invoiceTotal: '$139.99',
78-
hadDiscount: true,
78+
discountEnding: true,
7979
hasDifferentDiscount: true,
8080
},
8181
'Yearly Plan - Discount Changing'

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ subscriptionRenewalReminder-content-greeting = "Dear <%- productName %> customer
66

77
subscriptionRenewalReminder-content-intro = "Your current subscription is set to automatically renew in <%- reminderLength %> days."
88

9-
<% if (hadDiscount) { %>
9+
<% if (discountEnding) { %>
1010
subscriptionRenewalReminder-content-discount-ending = "Because a previous discount has ended, your subscription will renew at the standard price."
1111
<% } else if (hasDifferentDiscount) { %>
1212
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."

packages/fxa-auth-server/scripts/subscription-reminders.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ async function init() {
3737
DEFAULT_PLAN_LENGTH.toString()
3838
)
3939
.option(
40-
'-r, --reminder-length [days]',
40+
'-r, --monthly-renewal-reminder-length [days]',
4141
'Reminder length in days before the renewal date to send the reminder email for monthly plans. Defaults to 7.',
4242
DEFAULT_REMINDER_LENGTH.toString()
4343
)

0 commit comments

Comments
 (0)