mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-17 14:47:53 +01:00
increase Hourglasses and gemCapExtra promptly when multi-month subscription renews - fixes #4819 (#10147)
* allow Hourglasses and gemCapExtra to increase promptly after a multi-month subscription has renewed * fix existing Hourglass and Gem Cap tests that were wrong The scenario originally used for these two tests was a six-month recurring subscription (you can tell that from the starting offset having a non-zero value). For recurring subscriptions, we do NOT want to increase the consecutive month benefits as soon as the sixth month starts because the user has already been given a full six months' benefits in advance and they might cancel the subscription before it renews later in the sixth month. Therefore we want to give the extra benefits at the beginning of the seventh month (ideally we'd give them mid-month in the sixth month when the renewal happens but we don't have support for tracking renewal dates). So, the two changed tests were actually not correct for the case where the offset started as non-zero. These tests are correct for one-month recurring subscriptions (when the offset is never set to anything above zero). The user isn't meant to get any consecutive month benefits until a multiple of 3 months has been reached. * add tests for one-month recurring subscription before 3x months are reached * add tests for 3-, 6-, and 12-month recurring subscriptions The 3-month tests are the most thorough, stepping through the expected start and end values of consecutive data for a 7-month range. The 6-month tests are a bit less thorough since the same code is used for all multi-month periods. The discount Google subscription code is used to ensure we keep support for it. The 12-month tests are less thorough still, since again the same code is used. I'm about to try some more tests with `useFakeTimers`, which should be a better way to test the code since they won't rely on me having set the initial values correctly for each test. :) But I wanted to work through these cases manually first to ensure my understanding of how the values should change does actually match the code. * add tests for 1-, 3-, 6-, and 12-month recurring subscriptions using clock changes to simulate passing months Also fixed the clock call in an unrelated test because it was forming the date incorrectly (`unix()` can't be used to create a date). Also changed email@email.email to email@example.com because email@email.email is potentially a real email address. * add tests for 3-month gift subscriptions - no extra consecutive benefits given * add tests for consecutive benefits for 6-month recurring subscription that has incorrect consecutive month data because it started before issue #4819 was fixed * fix lint errors * remove outdated subscription tests
This commit is contained in:
@@ -59,6 +59,7 @@ let CLEAR_BUFFS = {
|
||||
};
|
||||
|
||||
function grantEndOfTheMonthPerks (user, now) {
|
||||
const SUBSCRIPTION_BASIC_BLOCK_LENGTH = 3; // multi-month subscriptions are for multiples of 3 months
|
||||
let plan = user.purchased.plan;
|
||||
let subscriptionEndDate = moment(plan.dateTerminated).isBefore() ? moment(plan.dateTerminated).startOf('month') : moment(now).startOf('month');
|
||||
let dateUpdatedMoment = moment(plan.dateUpdated).startOf('month');
|
||||
@@ -70,16 +71,49 @@ function grantEndOfTheMonthPerks (user, now) {
|
||||
// If they already got perks for those blocks (eg, 6mo subscription, subscription gifts, etc) - then dec the offset until it hits 0
|
||||
_.defaults(plan.consecutive, {count: 0, offset: 0, trinkets: 0, gemCapExtra: 0});
|
||||
|
||||
let planMonthsLength = 1; // 1 for one-month recurring or gift subscriptions; later set to 3 for 3-month recurring, etc.
|
||||
|
||||
for (let i = 0; i < elapsedMonths; i++) {
|
||||
plan.consecutive.count++;
|
||||
|
||||
if (plan.consecutive.offset > 1) {
|
||||
plan.consecutive.offset--;
|
||||
} else if (plan.consecutive.count % 3 === 0) { // every 3 months
|
||||
if (plan.consecutive.offset === 1) plan.consecutive.offset--;
|
||||
plan.consecutive.trinkets++;
|
||||
plan.consecutive.gemCapExtra += 5;
|
||||
if (plan.consecutive.gemCapExtra > 25) plan.consecutive.gemCapExtra = 25; // cap it at 50 (hard 25 limit + extra 25)
|
||||
plan.consecutive.offset--;
|
||||
// If offset is now greater than 0, the user is within a period for which they have already been given the consecutive months perks.
|
||||
//
|
||||
// If offset now equals 0, this is the final month for which the user has already been given the consecutive month perks.
|
||||
// We do not give them more perks yet because they might cancel the subscription before the next payment is taken.
|
||||
//
|
||||
// If offset is now less than 0, the user EITHER has a single-month recurring subscription and MIGHT be due for perks,
|
||||
// OR has a multi-month subscription that renewed some time in the previous calendar month and so they are due for a new set of perks
|
||||
// (strictly speaking, they should have been given the perks at the time that next payment was taken, but we don't have support for
|
||||
// tracking payments like that - giving the perks when offset is < 0 is a workaround).
|
||||
|
||||
if (plan.consecutive.offset < 0) {
|
||||
if (plan.planId) {
|
||||
// NB gift subscriptions don't have a planID (which doesn't matter because we don't need to reapply perks for them and by this point they should have expired anyway)
|
||||
let planIdRegExp = new RegExp('_([0-9]+)mo'); // e.g., matches 'google_6mo' / 'basic_12mo' and captures '6' / '12'
|
||||
let match = plan.planId.match(planIdRegExp);
|
||||
if (match !== null && match[0] !== null) {
|
||||
planMonthsLength = match[1]; // 3 for 3-month recurring subscription, etc
|
||||
}
|
||||
}
|
||||
|
||||
let perkAmountNeeded = 0; // every 3 months you get one set of perks - this variable records how many sets you need
|
||||
if (planMonthsLength === 1) {
|
||||
// User has a single-month recurring subscription and are due for perks IF they've been subscribed for a multiple of 3 months.
|
||||
if (plan.consecutive.count % SUBSCRIPTION_BASIC_BLOCK_LENGTH === 0) { // every 3 months
|
||||
perkAmountNeeded = 1;
|
||||
}
|
||||
plan.consecutive.offset = 0; // allow the same logic to be run next month
|
||||
} else {
|
||||
// User has a multi-month recurring subscription and it renewed in the previous calendar month.
|
||||
perkAmountNeeded = planMonthsLength / SUBSCRIPTION_BASIC_BLOCK_LENGTH; // e.g., for a 6-month subscription, give two sets of perks
|
||||
plan.consecutive.offset = planMonthsLength - 1; // don't need to check for perks again for this many months (subtract 1 because we should have run this when the payment was taken last month)
|
||||
}
|
||||
if (perkAmountNeeded > 0) {
|
||||
plan.consecutive.trinkets += perkAmountNeeded; // one Hourglass every 3 months
|
||||
plan.consecutive.gemCapExtra += 5 * perkAmountNeeded; // 5 extra Gems every 3 months
|
||||
if (plan.consecutive.gemCapExtra > 25) plan.consecutive.gemCapExtra = 25; // cap it at 50 (hard 25 limit + extra 25)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user