Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
</span>
</mj-text>

<% if (locals.hadDiscount) { %>
<% if (locals.discountEnding) { %>
<mj-text css-class="text-body">
<span data-l10n-id="subscriptionRenewalReminder-content-discount-ending">
Because a previous discount has ended, your subscription will renew at the standard price.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const data = {
reminderLength: '7',
subscriptionSupportUrl: 'http://localhost:3030/support',
updateBillingUrl: 'http://localhost:3030/subscriptions',
hadDiscount: false,
discountEnding: false,
hasDifferentDiscount: false,
};

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

export const MonthlyPlanDiscountEnding = createStory(
{
hadDiscount: true,
discountEnding: true,
},
'Monthly Plan - Discount Ending'
);
Expand All @@ -47,7 +47,7 @@ export const YearlyPlanNoDiscount = createStory(
planIntervalCount: '1',
reminderLength: '15',
invoiceTotal: '$199.99',
hadDiscount: false,
discountEnding: false,
},
'Yearly Plan - No Discount'
);
Expand All @@ -58,15 +58,15 @@ export const YearlyPlanDiscountEnding = createStory(
planIntervalCount: '1',
reminderLength: '15',
invoiceTotal: '$199.99',
hadDiscount: true,
discountEnding: true,
hasDifferentDiscount: false,
},
'Yearly Plan - Discount Ending'
);

export const MonthlyPlanDiscountChanging = createStory(
{
hadDiscount: true,
discountEnding: true,
hasDifferentDiscount: true,
invoiceTotal: '$14.00',
},
Expand All @@ -79,7 +79,7 @@ export const YearlyPlanDiscountChanging = createStory(
planIntervalCount: '1',
reminderLength: '15',
invoiceTotal: '$139.99',
hadDiscount: true,
discountEnding: true,
hasDifferentDiscount: true,
},
'Yearly Plan - Discount Changing'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export type TemplateData = SubscriptionSupportContactTemplateData &
reminderLength: string;
subscriptionSupportUrl: string;
updateBillingUrl: string;
hadDiscount?: boolean;
discountEnding?: boolean;
hasDifferentDiscount?: boolean;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ subscriptionRenewalReminder-content-greeting = "Dear <%- productName %> customer

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

<% if (locals.hadDiscount) { %>
<% if (locals.discountEnding) { %>
subscriptionRenewalReminder-content-discount-ending = "Because a previous discount has ended, your subscription will renew at the standard price."
<% } else if (locals.hasDifferentDiscount) { %>
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."
Expand Down
36 changes: 24 additions & 12 deletions packages/fxa-auth-server/lib/payments/subscription-reminders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -331,14 +331,6 @@ export class SubscriptionReminders {
}
try {
const account = await this.db.account(uid);
this.log.info('sendSubscriptionRenewalReminderEmail', {
message: 'Sending a renewal reminder email.',
subscriptionId: subscription.id,
currentPeriodStart: subscription.current_period_start,
currentPeriodEnd: subscription.current_period_end,
currentDateMs: Date.now(),
reminderLength: effectiveReminderDuration.as('days'),
});
const { email } = account;
const formattedSubscription =
await this.stripeHelper.formatSubscriptionForEmail(subscription);
Expand Down Expand Up @@ -368,10 +360,30 @@ export class SubscriptionReminders {
: null;

// Detect if discount is ending
const hadDiscount = this.hasDiscountEnding(currentDiscountId, upcomingDiscountId);
const discountEnding = this.hasDiscountEnding(currentDiscountId, upcomingDiscountId);
// Detect if renewal has a different discount
const hasDifferentDiscount = this.hasDifferentDiscount(currentDiscountId, upcomingDiscountId);

// Business rule: Monthly subscriptions only receive renewal reminders when a discount is ending,
// to avoid notification fatigue for standard monthly renewals.
if (interval === 'month' && !discountEnding) {
this.log.info('sendSubscriptionRenewalReminderEmail.skippingMonthlyNoDiscount', {
subscriptionId: subscription.id,
planId,
});
return false;
}

// If we reach here, we're sending the email
this.log.info('sendSubscriptionRenewalReminderEmail', {
message: 'Sending a renewal reminder email.',
subscriptionId: subscription.id,
currentPeriodStart: subscription.current_period_start,
currentPeriodEnd: subscription.current_period_end,
currentDateMs: Date.now(),
reminderLength: effectiveReminderDuration.as('days'),
});

await this.mailer.sendSubscriptionRenewalReminderEmail(
account.emails,
account,
Expand All @@ -388,7 +400,7 @@ export class SubscriptionReminders {
invoiceTotalCurrency: invoicePreview.currency,
productMetadata: formattedSubscription.productMetadata,
planConfig: formattedSubscription.planConfig,
hadDiscount,
discountEnding,
hasDifferentDiscount,
}
);
Expand Down Expand Up @@ -488,8 +500,8 @@ export class SubscriptionReminders {
* Sends a reminder email for all active subscriptions for all plans
* as long or longer than `planLength`:
* 1. Get a list of all plans of sufficient `planLength`
* 2. Send 30-day reminders for yearly plans (if enabled)
* 3. Send 14-day reminders for all plans
* 2. Send 15-day reminders for yearly plans (if enabled)
* 3. Send 7-day reminders for monthly plans
* 4. If enabled, send subscription ending reminder emails if one
* hasn't already been sent.
*/
Expand Down
2 changes: 1 addition & 1 deletion packages/fxa-auth-server/lib/senders/email.js
Original file line number Diff line number Diff line change
Expand Up @@ -3252,7 +3252,7 @@ module.exports = function (log, config, bounces, statsd) {
message.invoiceTotalCurrency,
message.acceptLanguage
),
hadDiscount: message.hadDiscount || false,
discountEnding: message.discountEnding || false,
hasDifferentDiscount: message.hasDifferentDiscount || false,
},
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
</span>
</mj-text>

<% if (hadDiscount) { %>
<% if (discountEnding) { %>
<mj-text css-class="text-body">
<span data-l10n-id="subscriptionRenewalReminder-content-discount-ending">
Because a previous discount has ended, your subscription will renew at the standard price.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const createStory = subplatStoryWithProps(
reminderLength: '7',
subscriptionSupportUrl: 'http://localhost:3030/support',
updateBillingUrl: 'http://localhost:3030/subscriptions',
hadDiscount: false,
discountEnding: false,
hasDifferentDiscount: false,
}
);
Expand All @@ -32,7 +32,7 @@ export const MonthlyPlanNoDiscount = createStory(

export const MonthlyPlanDiscountEnding = createStory(
{
hadDiscount: true,
discountEnding: true,
},
'Monthly Plan - Discount Ending'
);
Expand All @@ -43,7 +43,7 @@ export const YearlyPlanNoDiscount = createStory(
planIntervalCount: '1',
reminderLength: '15',
invoiceTotal: '$199.99',
hadDiscount: false,
discountEnding: false,
},
'Yearly Plan - No Discount'
);
Expand All @@ -54,15 +54,15 @@ export const YearlyPlanDiscountEnding = createStory(
planIntervalCount: '1',
reminderLength: '15',
invoiceTotal: '$199.99',
hadDiscount: true,
discountEnding: true,
hasDifferentDiscount: false,
},
'Yearly Plan - Discount Ending'
);

export const MonthlyPlanDiscountChanging = createStory(
{
hadDiscount: true,
discountEnding: true,
hasDifferentDiscount: true,
invoiceTotal: '$14.00',
},
Expand All @@ -75,7 +75,7 @@ export const YearlyPlanDiscountChanging = createStory(
planIntervalCount: '1',
reminderLength: '15',
invoiceTotal: '$139.99',
hadDiscount: true,
discountEnding: true,
hasDifferentDiscount: true,
},
'Yearly Plan - Discount Changing'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ subscriptionRenewalReminder-content-greeting = "Dear <%- productName %> customer

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

<% if (hadDiscount) { %>
<% if (discountEnding) { %>
subscriptionRenewalReminder-content-discount-ending = "Because a previous discount has ended, your subscription will renew at the standard price."
<% } else if (hasDifferentDiscount) { %>
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."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ async function init() {
DEFAULT_PLAN_LENGTH.toString()
)
.option(
'-r, --reminder-length [days]',
'-r, --monthly-renewal-reminder-length [days]',
'Reminder length in days before the renewal date to send the reminder email for monthly plans. Defaults to 7.',
DEFAULT_REMINDER_LENGTH.toString()
)
Expand Down
Loading
Loading