From da75b35d692c38699bb0252e565b55dda2bc4d2d Mon Sep 17 00:00:00 2001 From: Phillip Thelen Date: Tue, 6 Aug 2024 16:28:16 +0200 Subject: [PATCH 01/21] begin removing obsolete tests --- test/api/unit/libs/cron.test.js | 476 +------------------ test/api/unit/libs/payments/payments.test.js | 420 +++------------- 2 files changed, 88 insertions(+), 808 deletions(-) diff --git a/test/api/unit/libs/cron.test.js b/test/api/unit/libs/cron.test.js index 6757228033e..53d732b8ad4 100644 --- a/test/api/unit/libs/cron.test.js +++ b/test/api/unit/libs/cron.test.js @@ -163,14 +163,6 @@ describe('cron', async () => { expect(user.purchased.plan.consecutive.count).to.equal(2); }); - it('decrements plan.consecutive.offset when offset is greater than 0', async () => { - user.purchased.plan.consecutive.offset = 2; - await cron({ - user, tasksByType, daysMissed, analytics, - }); - expect(user.purchased.plan.consecutive.offset).to.equal(1); - }); - it('does not award unearned plan.consecutive.trinkets if subscription ended during an absence', async () => { user.purchased.plan.dateUpdated = moment().subtract(6, 'months').toDate(); user.purchased.plan.dateTerminated = moment().subtract(3, 'months').toDate(); @@ -185,12 +177,12 @@ describe('cron', async () => { }); it('does not increment plan.consecutive.gemCapExtra when user has reached the gemCap limit', async () => { - user.purchased.plan.consecutive.gemCapExtra = 25; + user.purchased.plan.consecutive.gemCapExtra = 26; user.purchased.plan.consecutive.count = 5; await cron({ user, tasksByType, daysMissed, analytics, }); - expect(user.purchased.plan.consecutive.gemCapExtra).to.equal(25); + expect(user.purchased.plan.consecutive.gemCapExtra).to.equal(26); }); it('does not reset plan stats if we are before the last day of the cancelled month', async () => { @@ -237,12 +229,11 @@ describe('cron', async () => { user1.purchased.plan.planId = 'basic'; user1.purchased.plan.consecutive.count = 0; user1.purchased.plan.perkMonthCount = 0; - user1.purchased.plan.consecutive.offset = 0; user1.purchased.plan.consecutive.trinkets = 0; user1.purchased.plan.consecutive.gemCapExtra = 0; }); - it('does not increment consecutive benefits after the first month', async () => { + it('increments consecutive benefits', async () => { clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(1, 'months') .add(2, 'days') .toDate()); @@ -253,75 +244,8 @@ describe('cron', async () => { user: user1, tasksByType, daysMissed, analytics, }); expect(user1.purchased.plan.consecutive.count).to.equal(1); - expect(user1.purchased.plan.consecutive.offset).to.equal(0); - expect(user1.purchased.plan.consecutive.trinkets).to.equal(0); - expect(user1.purchased.plan.consecutive.gemCapExtra).to.equal(0); - }); - - it('does not increment consecutive benefits after the second month', async () => { - clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(2, 'months') - .add(2, 'days') - .toDate()); - // Add 1 month to simulate what happens a month after the subscription was created. - // Add 2 days so that we're sure we're not affected by any start-of-month effects - // e.g., from time zone oddness. - await cron({ - user: user1, tasksByType, daysMissed, analytics, - }); - expect(user1.purchased.plan.consecutive.count).to.equal(2); - expect(user1.purchased.plan.consecutive.offset).to.equal(0); - expect(user1.purchased.plan.consecutive.trinkets).to.equal(0); - expect(user1.purchased.plan.consecutive.gemCapExtra).to.equal(0); - }); - - it('increments consecutive benefits after the second month if they also received a 1 month gift subscription', async () => { - user1.purchased.plan.perkMonthCount = 1; - clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(2, 'months') - .add(2, 'days') - .toDate()); - // Add 1 month to simulate what happens a month after the subscription was created. - // Add 2 days so that we're sure we're not affected by any start-of-month effects - // e.g., from time zone oddness. - await cron({ - user: user1, tasksByType, daysMissed, analytics, - }); - expect(user1.purchased.plan.perkMonthCount).to.equal(0); - expect(user1.purchased.plan.consecutive.count).to.equal(2); - expect(user1.purchased.plan.consecutive.offset).to.equal(0); - expect(user1.purchased.plan.consecutive.trinkets).to.equal(1); - expect(user1.purchased.plan.consecutive.gemCapExtra).to.equal(5); - }); - - it('increments consecutive benefits after the third month', async () => { - clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(3, 'months') - .add(2, 'days') - .toDate()); - // Add 1 month to simulate what happens a month after the subscription was created. - // Add 2 days so that we're sure we're not affected by any start-of-month effects - // e.g., from time zone oddness. - await cron({ - user: user1, tasksByType, daysMissed, analytics, - }); - expect(user1.purchased.plan.consecutive.count).to.equal(3); - expect(user1.purchased.plan.consecutive.offset).to.equal(0); - expect(user1.purchased.plan.consecutive.trinkets).to.equal(1); - expect(user1.purchased.plan.consecutive.gemCapExtra).to.equal(5); - }); - - it('does not increment consecutive benefits after the fourth month', async () => { - clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(4, 'months') - .add(2, 'days') - .toDate()); - // Add 1 month to simulate what happens a month after the subscription was created. - // Add 2 days so that we're sure we're not affected by any start-of-month effects - // e.g., from time zone oddness. - await cron({ - user: user1, tasksByType, daysMissed, analytics, - }); - expect(user1.purchased.plan.consecutive.count).to.equal(4); - expect(user1.purchased.plan.consecutive.offset).to.equal(0); - expect(user1.purchased.plan.consecutive.trinkets).to.equal(1); - expect(user1.purchased.plan.consecutive.gemCapExtra).to.equal(5); + expect(user1.purchased.plan.consecutive.trinkets).to.equal(2); + expect(user1.purchased.plan.consecutive.gemCapExtra).to.equal(2); }); it('increments consecutive benefits correctly if user has been absent with continuous subscription', async () => { @@ -332,33 +256,8 @@ describe('cron', async () => { user: user1, tasksByType, daysMissed, analytics, }); expect(user1.purchased.plan.consecutive.count).to.equal(10); - expect(user1.purchased.plan.consecutive.offset).to.equal(0); - expect(user1.purchased.plan.consecutive.trinkets).to.equal(3); - expect(user1.purchased.plan.consecutive.gemCapExtra).to.equal(15); - }); - - it('initializes plan.perkMonthCount if necessary', async () => { - user.purchased.plan.perkMonthCount = undefined; - clock = sinon.useFakeTimers(moment(user.purchased.plan.dateUpdated) - .utcOffset(0) - .startOf('month') - .add(1, 'months') - .add(2, 'days') - .toDate()); - await cron({ - user, tasksByType, daysMissed, analytics, - }); - expect(user.purchased.plan.perkMonthCount).to.equal(1); - user.purchased.plan.perkMonthCount = undefined; - user.purchased.plan.consecutive.count = 8; - clock.restore(); - clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(2, 'months') - .add(2, 'days') - .toDate()); - await cron({ - user, tasksByType, daysMissed, analytics, - }); - expect(user.purchased.plan.perkMonthCount).to.equal(2); + expect(user1.purchased.plan.consecutive.trinkets).to.equal(10); + expect(user1.purchased.plan.consecutive.gemCapExtra).to.equal(20); }); }); @@ -381,12 +280,11 @@ describe('cron', async () => { user3.purchased.plan.planId = 'basic_3mo'; user3.purchased.plan.perkMonthCount = 0; user3.purchased.plan.consecutive.count = 0; - user3.purchased.plan.consecutive.offset = 3; user3.purchased.plan.consecutive.trinkets = 1; user3.purchased.plan.consecutive.gemCapExtra = 5; }); - it('does not increment consecutive benefits in the first month of the first paid period that they already have benefits for', async () => { + it('increments consecutive benefits', async () => { clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(1, 'months') .add(2, 'days') .toDate()); @@ -394,102 +292,8 @@ describe('cron', async () => { user: user3, tasksByType, daysMissed, analytics, }); expect(user3.purchased.plan.consecutive.count).to.equal(1); - expect(user3.purchased.plan.consecutive.offset).to.equal(2); - expect(user3.purchased.plan.consecutive.trinkets).to.equal(1); - expect(user3.purchased.plan.consecutive.gemCapExtra).to.equal(5); - }); - - it('does not increment consecutive benefits in the middle of the period that they already have benefits for', async () => { - clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(2, 'months') - .add(2, 'days') - .toDate()); - await cron({ - user: user3, tasksByType, daysMissed, analytics, - }); - expect(user3.purchased.plan.consecutive.count).to.equal(2); - expect(user3.purchased.plan.consecutive.offset).to.equal(1); - expect(user3.purchased.plan.consecutive.trinkets).to.equal(1); - expect(user3.purchased.plan.consecutive.gemCapExtra).to.equal(5); - }); - - it('does not increment consecutive benefits in the final month of the period that they already have benefits for', async () => { - clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(3, 'months') - .add(2, 'days') - .toDate()); - await cron({ - user: user3, tasksByType, daysMissed, analytics, - }); - expect(user3.purchased.plan.consecutive.count).to.equal(3); - expect(user3.purchased.plan.consecutive.offset).to.equal(0); - expect(user3.purchased.plan.consecutive.trinkets).to.equal(1); - expect(user3.purchased.plan.consecutive.gemCapExtra).to.equal(5); - }); - - it('increments consecutive benefits the month after the second paid period has started', async () => { - clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(4, 'months') - .add(2, 'days') - .toDate()); - await cron({ - user: user3, tasksByType, daysMissed, analytics, - }); - expect(user3.purchased.plan.consecutive.count).to.equal(4); - expect(user3.purchased.plan.consecutive.offset).to.equal(2); - expect(user3.purchased.plan.consecutive.trinkets).to.equal(2); - expect(user3.purchased.plan.consecutive.gemCapExtra).to.equal(10); - }); - - it('keeps existing plan.perkMonthCount intact when incrementing consecutive benefits', async () => { - user3.purchased.plan.perkMonthCount = 2; - user3.purchased.plan.consecutive.trinkets = 1; - user3.purchased.plan.consecutive.gemCapExtra = 5; - clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(4, 'months') - .add(2, 'days') - .toDate()); - await cron({ - user: user3, tasksByType, daysMissed, analytics, - }); - expect(user3.purchased.plan.perkMonthCount).to.equal(2); expect(user3.purchased.plan.consecutive.trinkets).to.equal(2); - expect(user3.purchased.plan.consecutive.gemCapExtra).to.equal(10); - }); - - it('does not increment consecutive benefits in the second month of the second period that they already have benefits for', async () => { - clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(5, 'months') - .add(2, 'days') - .toDate()); - await cron({ - user: user3, tasksByType, daysMissed, analytics, - }); - expect(user3.purchased.plan.consecutive.count).to.equal(5); - expect(user3.purchased.plan.consecutive.offset).to.equal(1); - expect(user3.purchased.plan.consecutive.trinkets).to.equal(2); - expect(user3.purchased.plan.consecutive.gemCapExtra).to.equal(10); - }); - - it('does not increment consecutive benefits in the final month of the second period that they already have benefits for', async () => { - clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(6, 'months') - .add(2, 'days') - .toDate()); - await cron({ - user: user3, tasksByType, daysMissed, analytics, - }); - expect(user3.purchased.plan.consecutive.count).to.equal(6); - expect(user3.purchased.plan.consecutive.offset).to.equal(0); - expect(user3.purchased.plan.consecutive.trinkets).to.equal(2); - expect(user3.purchased.plan.consecutive.gemCapExtra).to.equal(10); - }); - - it('increments consecutive benefits the month after the third paid period has started', async () => { - clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(7, 'months') - .add(2, 'days') - .toDate()); - await cron({ - user: user3, tasksByType, daysMissed, analytics, - }); - expect(user3.purchased.plan.consecutive.count).to.equal(7); - expect(user3.purchased.plan.consecutive.offset).to.equal(2); - expect(user3.purchased.plan.consecutive.trinkets).to.equal(3); - expect(user3.purchased.plan.consecutive.gemCapExtra).to.equal(15); + expect(user3.purchased.plan.consecutive.gemCapExtra).to.equal(2); }); it('increments consecutive benefits correctly if user has been absent with continuous subscription', async () => { @@ -500,8 +304,7 @@ describe('cron', async () => { user: user3, tasksByType, daysMissed, analytics, }); expect(user3.purchased.plan.consecutive.count).to.equal(10); - expect(user3.purchased.plan.consecutive.offset).to.equal(2); - expect(user3.purchased.plan.consecutive.trinkets).to.equal(4); + expect(user3.purchased.plan.consecutive.trinkets).to.equal(10); expect(user3.purchased.plan.consecutive.gemCapExtra).to.equal(20); }); }); @@ -525,12 +328,11 @@ describe('cron', async () => { user6.purchased.plan.planId = 'google_6mo'; user6.purchased.plan.perkMonthCount = 0; user6.purchased.plan.consecutive.count = 0; - user6.purchased.plan.consecutive.offset = 6; user6.purchased.plan.consecutive.trinkets = 2; user6.purchased.plan.consecutive.gemCapExtra = 10; }); - it('does not increment consecutive benefits in the first month of the first paid period that they already have benefits for', async () => { + it('increments benefits', async () => { clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(1, 'months') .add(2, 'days') .toDate()); @@ -538,74 +340,8 @@ describe('cron', async () => { user: user6, tasksByType, daysMissed, analytics, }); expect(user6.purchased.plan.consecutive.count).to.equal(1); - expect(user6.purchased.plan.consecutive.offset).to.equal(5); - expect(user6.purchased.plan.consecutive.trinkets).to.equal(2); - expect(user6.purchased.plan.consecutive.gemCapExtra).to.equal(10); - }); - - it('does not increment consecutive benefits in the final month of the period that they already have benefits for', async () => { - clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(6, 'months') - .add(2, 'days') - .toDate()); - await cron({ - user: user6, tasksByType, daysMissed, analytics, - }); - expect(user6.purchased.plan.consecutive.count).to.equal(6); - expect(user6.purchased.plan.consecutive.offset).to.equal(0); expect(user6.purchased.plan.consecutive.trinkets).to.equal(2); - expect(user6.purchased.plan.consecutive.gemCapExtra).to.equal(10); - }); - - it('increments consecutive benefits the month after the second paid period has started', async () => { - clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(7, 'months') - .add(2, 'days') - .toDate()); - await cron({ - user: user6, tasksByType, daysMissed, analytics, - }); - expect(user6.purchased.plan.consecutive.count).to.equal(7); - expect(user6.purchased.plan.consecutive.offset).to.equal(5); - expect(user6.purchased.plan.consecutive.trinkets).to.equal(4); - expect(user6.purchased.plan.consecutive.gemCapExtra).to.equal(20); - }); - - it('keeps existing plan.perkMonthCount intact when incrementing consecutive benefits', async () => { - user6.purchased.plan.perkMonthCount = 2; - clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(7, 'months') - .add(2, 'days') - .toDate()); - await cron({ - user: user6, tasksByType, daysMissed, analytics, - }); - expect(user6.purchased.plan.perkMonthCount).to.equal(2); - expect(user6.purchased.plan.consecutive.trinkets).to.equal(4); - expect(user6.purchased.plan.consecutive.gemCapExtra).to.equal(20); - }); - - it('increments consecutive benefits the month after the third paid period has started', async () => { - clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(13, 'months') - .add(2, 'days') - .toDate()); - await cron({ - user: user6, tasksByType, daysMissed, analytics, - }); - expect(user6.purchased.plan.consecutive.count).to.equal(13); - expect(user6.purchased.plan.consecutive.offset).to.equal(5); - expect(user6.purchased.plan.consecutive.trinkets).to.equal(6); - expect(user6.purchased.plan.consecutive.gemCapExtra).to.equal(25); - }); - - it('increments consecutive benefits correctly if user has been absent with continuous subscription', async () => { - clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(19, 'months') - .add(2, 'days') - .toDate()); - await cron({ - user: user6, tasksByType, daysMissed, analytics, - }); - expect(user6.purchased.plan.consecutive.count).to.equal(19); - expect(user6.purchased.plan.consecutive.offset).to.equal(5); - expect(user6.purchased.plan.consecutive.trinkets).to.equal(8); - expect(user6.purchased.plan.consecutive.gemCapExtra).to.equal(25); + expect(user6.purchased.plan.consecutive.gemCapExtra).to.equal(2); }); }); @@ -626,11 +362,10 @@ describe('cron', async () => { user12.purchased.plan.dateUpdated = moment().toDate(); user12.purchased.plan.planId = 'basic_12mo'; user12.purchased.plan.consecutive.count = 0; - user12.purchased.plan.consecutive.offset = 12; user12.purchased.plan.consecutive.trinkets = 4; user12.purchased.plan.consecutive.gemCapExtra = 20; - it('does not increment consecutive benefits in the first month of the first paid period that they already have benefits for', async () => { + it('increments consecutive benefits the month after the second paid period has started', async () => { clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(1, 'months') .add(2, 'days') .toDate()); @@ -638,61 +373,20 @@ describe('cron', async () => { user: user12, tasksByType, daysMissed, analytics, }); expect(user12.purchased.plan.consecutive.count).to.equal(1); - expect(user12.purchased.plan.consecutive.offset).to.equal(11); - expect(user12.purchased.plan.consecutive.trinkets).to.equal(4); - expect(user12.purchased.plan.consecutive.gemCapExtra).to.equal(20); - }); - - it('does not increment consecutive benefits in the final month of the period that they already have benefits for', async () => { - clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(12, 'months') - .add(2, 'days') - .toDate()); - await cron({ - user: user12, tasksByType, daysMissed, analytics, - }); - expect(user12.purchased.plan.consecutive.count).to.equal(12); - expect(user12.purchased.plan.consecutive.offset).to.equal(0); - expect(user12.purchased.plan.consecutive.trinkets).to.equal(4); - expect(user12.purchased.plan.consecutive.gemCapExtra).to.equal(20); - }); - - it('increments consecutive benefits the month after the second paid period has started', async () => { - clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(13, 'months') - .add(2, 'days') - .toDate()); - await cron({ - user: user12, tasksByType, daysMissed, analytics, - }); - expect(user12.purchased.plan.consecutive.count).to.equal(13); - expect(user12.purchased.plan.consecutive.offset).to.equal(11); - expect(user12.purchased.plan.consecutive.trinkets).to.equal(8); - expect(user12.purchased.plan.consecutive.gemCapExtra).to.equal(25); - }); - - it('increments consecutive benefits the month after the third paid period has started', async () => { - clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(25, 'months') - .add(2, 'days') - .toDate()); - await cron({ - user: user12, tasksByType, daysMissed, analytics, - }); - expect(user12.purchased.plan.consecutive.count).to.equal(25); - expect(user12.purchased.plan.consecutive.offset).to.equal(11); - expect(user12.purchased.plan.consecutive.trinkets).to.equal(12); - expect(user12.purchased.plan.consecutive.gemCapExtra).to.equal(25); + expect(user12.purchased.plan.consecutive.trinkets).to.equal(13); + expect(user12.purchased.plan.consecutive.gemCapExtra).to.equal(26); }); it('increments consecutive benefits correctly if user has been absent with continuous subscription', async () => { - clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(37, 'months') + clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(10, 'months') .add(2, 'days') .toDate()); await cron({ user: user12, tasksByType, daysMissed, analytics, }); - expect(user12.purchased.plan.consecutive.count).to.equal(37); - expect(user12.purchased.plan.consecutive.offset).to.equal(11); - expect(user12.purchased.plan.consecutive.trinkets).to.equal(16); - expect(user12.purchased.plan.consecutive.gemCapExtra).to.equal(25); + expect(user12.purchased.plan.consecutive.count).to.equal(10); + expect(user12.purchased.plan.consecutive.trinkets).to.equal(22); + expect(user12.purchased.plan.consecutive.gemCapExtra).to.equal(65); }); }); @@ -715,43 +409,16 @@ describe('cron', async () => { .toDate(); user3g.purchased.plan.planId = null; user3g.purchased.plan.consecutive.count = 0; - user3g.purchased.plan.consecutive.offset = 3; user3g.purchased.plan.consecutive.trinkets = 1; user3g.purchased.plan.consecutive.gemCapExtra = 5; - it('does not increment consecutive benefits in the first month of the gift subscription', async () => { + it('increments benefits', async () => { clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(1, 'months') .add(2, 'days') .toDate()); await cron({ user: user3g, tasksByType, daysMissed, analytics, }); - expect(user3g.purchased.plan.consecutive.count).to.equal(1); - expect(user3g.purchased.plan.consecutive.offset).to.equal(2); - expect(user3g.purchased.plan.consecutive.trinkets).to.equal(1); - expect(user3g.purchased.plan.consecutive.gemCapExtra).to.equal(5); - }); - - it('does not increment consecutive benefits in the second month of the gift subscription', async () => { - clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(2, 'months') - .add(2, 'days') - .toDate()); - await cron({ - user: user3g, tasksByType, daysMissed, analytics, - }); - expect(user3g.purchased.plan.consecutive.count).to.equal(2); - expect(user3g.purchased.plan.consecutive.offset).to.equal(1); - expect(user3g.purchased.plan.consecutive.trinkets).to.equal(1); - expect(user3g.purchased.plan.consecutive.gemCapExtra).to.equal(5); - }); - - it('does not increment consecutive benefits in the third month of the gift subscription', async () => { - clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(3, 'months') - .add(2, 'days') - .toDate()); - await cron({ - user: user3g, tasksByType, daysMissed, analytics, - }); expect(user3g.purchased.plan.consecutive.count).to.equal(3); expect(user3g.purchased.plan.consecutive.offset).to.equal(0); expect(user3g.purchased.plan.consecutive.trinkets).to.equal(1); @@ -772,81 +439,6 @@ describe('cron', async () => { expect(user3g.purchased.plan.consecutive.gemCapExtra).to.equal(0); // erased }); }); - - describe('for a 6-month recurring subscription where the user has incorrect consecutive month data from prior bugs', async () => { - const user6x = new User({ - auth: { - local: { - username: 'username6x', - lowerCaseUsername: 'username6x', - email: 'email6x@example.com', - salt: 'salt', - hashed_password: 'hashed_password', // eslint-disable-line camelcase - }, - }, - }); - // user6x has a 6-month recurring subscription starting 8 months in the past - // before issue #4819 was fixed - user6x.purchased.plan.customerId = 'subscribedId'; - user6x.purchased.plan.dateUpdated = moment().toDate(); - user6x.purchased.plan.planId = 'basic_6mo'; - user6x.purchased.plan.consecutive.count = 8; - user6x.purchased.plan.consecutive.offset = 0; - user6x.purchased.plan.consecutive.trinkets = 3; - user6x.purchased.plan.consecutive.gemCapExtra = 15; - - it('increments consecutive benefits in the first month since the fix for #4819 goes live', async () => { - clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(1, 'months') - .add(2, 'days') - .toDate()); - await cron({ - user: user6x, tasksByType, daysMissed, analytics, - }); - expect(user6x.purchased.plan.consecutive.count).to.equal(9); - expect(user6x.purchased.plan.consecutive.offset).to.equal(5); - expect(user6x.purchased.plan.consecutive.trinkets).to.equal(5); - expect(user6x.purchased.plan.consecutive.gemCapExtra).to.equal(25); - }); - - it('does not increment consecutive benefits in the second month after the fix goes live', async () => { - clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(2, 'months') - .add(2, 'days') - .toDate()); - await cron({ - user: user6x, tasksByType, daysMissed, analytics, - }); - expect(user6x.purchased.plan.consecutive.count).to.equal(10); - expect(user6x.purchased.plan.consecutive.offset).to.equal(4); - expect(user6x.purchased.plan.consecutive.trinkets).to.equal(5); - expect(user6x.purchased.plan.consecutive.gemCapExtra).to.equal(25); - }); - - it('does not increment consecutive benefits in the third month after the fix goes live', async () => { - clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(3, 'months') - .add(2, 'days') - .toDate()); - await cron({ - user: user6x, tasksByType, daysMissed, analytics, - }); - expect(user6x.purchased.plan.consecutive.count).to.equal(11); - expect(user6x.purchased.plan.consecutive.offset).to.equal(3); - expect(user6x.purchased.plan.consecutive.trinkets).to.equal(5); - expect(user6x.purchased.plan.consecutive.gemCapExtra).to.equal(25); - }); - - it('increments consecutive benefits in the seventh month after the fix goes live', async () => { - clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(7, 'months') - .add(2, 'days') - .toDate()); - await cron({ - user: user6x, tasksByType, daysMissed, analytics, - }); - expect(user6x.purchased.plan.consecutive.count).to.equal(15); - expect(user6x.purchased.plan.consecutive.offset).to.equal(5); - expect(user6x.purchased.plan.consecutive.trinkets).to.equal(7); - expect(user6x.purchased.plan.consecutive.gemCapExtra).to.equal(25); - }); - }); }); describe('end of the month perks when user is not subscribed', async () => { @@ -888,14 +480,6 @@ describe('cron', async () => { expect(user.purchased.plan.consecutive.count).to.equal(0); }); - it('does not decrement plan.consecutive.offset when offset is greater than 0', async () => { - user.purchased.plan.consecutive.offset = 1; - await cron({ - user, tasksByType, daysMissed, analytics, - }); - expect(user.purchased.plan.consecutive.offset).to.equal(1); - }); - it('does not increment plan.consecutive.trinkets when user has reached a month that is a multiple of 3', async () => { user.purchased.plan.consecutive.count = 5; await cron({ @@ -913,12 +497,12 @@ describe('cron', async () => { }); it('does not increment plan.consecutive.gemCapExtra when user has reached the gemCap limit', async () => { - user.purchased.plan.consecutive.gemCapExtra = 25; + user.purchased.plan.consecutive.gemCapExtra = 26; user.purchased.plan.consecutive.count = 5; await cron({ user, tasksByType, daysMissed, analytics, }); - expect(user.purchased.plan.consecutive.gemCapExtra).to.equal(25); + expect(user.purchased.plan.consecutive.gemCapExtra).to.equal(26); }); it('does nothing to plan stats if we are before the last day of the cancelled month', async () => { @@ -928,22 +512,6 @@ describe('cron', async () => { }); expect(user.purchased.plan.customerId).to.not.exist; }); - - xit('does nothing to plan stats when we are after the last day of the cancelled month', async () => { - user.purchased.plan.dateTerminated = moment(new Date()).subtract({ days: 1 }); - user.purchased.plan.consecutive.gemCapExtra = 20; - user.purchased.plan.consecutive.count = 5; - user.purchased.plan.consecutive.offset = 1; - - await cron({ - user, tasksByType, daysMissed, analytics, - }); - - expect(user.purchased.plan.customerId).to.exist; - expect(user.purchased.plan.consecutive.gemCapExtra).to.exist; - expect(user.purchased.plan.consecutive.count).to.exist; - expect(user.purchased.plan.consecutive.offset).to.exist; - }); }); describe('todos', async () => { diff --git a/test/api/unit/libs/payments/payments.test.js b/test/api/unit/libs/payments/payments.test.js index 5b2d2f98990..5fc08e9f196 100644 --- a/test/api/unit/libs/payments/payments.test.js +++ b/test/api/unit/libs/payments/payments.test.js @@ -177,6 +177,37 @@ describe('payments/index', () => { expect(recipient.purchased.plan.dateUpdated).to.exist; }); + it('does not reset gemCapExtra if they already had one', async () => { + recipient.purchased.plan.gemCapExtra = 10; + + await api.createSubscription(data); + + expect(recipient.purchased.plan.gemCapExtra).to.eql(10); + }); + + it('sets gemCapExtra to max if they receive a 12 month sub', async () => { + recipient.purchased.plan.gemCapExtra = 10; + + data.gift.subscription.key = 'basic_12mo'; + data.gift.subscription.months = 12; + + await api.createSubscription(data); + + expect(recipient.purchased.plan.gemCapExtra).to.eql(26); + }); + + it('gives user 1 hourglass if they have no active subscription', async () => { + await api.createSubscription(data); + + expect(recipient.purchased.plan.trinket).to.eql(1); + }); + + it('does not giec any hourglasses if they have an active subscription', async () => { + recipient.purchased.plan = plan; + await api.createSubscription(data); + expect(recipient.purchased.plan.trinket).to.eql(plan.trinket); + }); + it('sets plan.dateUpdated if it did exist but the user has cancelled', async () => { recipient.purchased.plan.dateUpdated = moment().subtract(1, 'days').toDate(); recipient.purchased.plan.dateTerminated = moment().subtract(1, 'days').toDate(); @@ -235,116 +266,6 @@ describe('payments/index', () => { expect(recipient.purchased.plan.customerId).to.eql('customer-id'); }); - it('sets plan.perkMonthCount to 1 if user is not subscribed', async () => { - recipient.purchased.plan = plan; - recipient.purchased.plan.perkMonthCount = 1; - recipient.purchased.plan.customerId = undefined; - data.sub.key = 'basic_earned'; - data.gift.subscription.key = 'basic_earned'; - data.gift.subscription.months = 1; - - expect(recipient.purchased.plan.perkMonthCount).to.eql(1); - await api.createSubscription(data); - - expect(recipient.purchased.plan.perkMonthCount).to.eql(1); - }); - - it('sets plan.perkMonthCount to 1 if field is not initialized', async () => { - recipient.purchased.plan = plan; - recipient.purchased.plan.perkMonthCount = -1; - recipient.purchased.plan.customerId = undefined; - data.sub.key = 'basic_earned'; - data.gift.subscription.key = 'basic_earned'; - data.gift.subscription.months = 1; - - expect(recipient.purchased.plan.perkMonthCount).to.eql(-1); - await api.createSubscription(data); - - expect(recipient.purchased.plan.perkMonthCount).to.eql(1); - }); - - it('sets plan.perkMonthCount to 1 if user had previous count but lapsed subscription', async () => { - recipient.purchased.plan = plan; - recipient.purchased.plan.perkMonthCount = 2; - recipient.purchased.plan.customerId = undefined; - data.sub.key = 'basic_earned'; - data.gift.subscription.key = 'basic_earned'; - data.gift.subscription.months = 1; - - expect(recipient.purchased.plan.perkMonthCount).to.eql(2); - await api.createSubscription(data); - - expect(recipient.purchased.plan.perkMonthCount).to.eql(1); - }); - - it('adds to plan.perkMonthCount if user is already subscribed', async () => { - recipient.purchased.plan = plan; - recipient.purchased.plan.perkMonthCount = 1; - data.sub.key = 'basic_earned'; - data.gift.subscription.key = 'basic_earned'; - data.gift.subscription.months = 1; - - expect(recipient.purchased.plan.perkMonthCount).to.eql(1); - await api.createSubscription(data); - - expect(recipient.purchased.plan.perkMonthCount).to.eql(2); - }); - - it('awards perks if plan.perkMonthCount reaches 3 with existing subscription', async () => { - recipient.purchased.plan = plan; - recipient.purchased.plan.perkMonthCount = 2; - data.sub.key = 'basic_earned'; - data.gift.subscription.key = 'basic_earned'; - data.gift.subscription.months = 1; - - expect(recipient.purchased.plan.perkMonthCount).to.eql(2); - expect(recipient.purchased.plan.consecutive.trinkets).to.eql(0); - expect(recipient.purchased.plan.consecutive.gemCapExtra).to.eql(0); - await api.createSubscription(data); - - expect(recipient.purchased.plan.perkMonthCount).to.eql(0); - expect(recipient.purchased.plan.consecutive.trinkets).to.eql(1); - expect(recipient.purchased.plan.consecutive.gemCapExtra).to.eql(5); - }); - - it('awards perks if plan.perkMonthCount reaches 3 without existing subscription', async () => { - recipient.purchased.plan.perkMonthCount = 0; - expect(recipient.purchased.plan.perkMonthCount).to.eql(0); - expect(recipient.purchased.plan.consecutive.trinkets).to.eql(0); - expect(recipient.purchased.plan.consecutive.gemCapExtra).to.eql(0); - await api.createSubscription(data); - - expect(recipient.purchased.plan.perkMonthCount).to.eql(0); - expect(recipient.purchased.plan.consecutive.trinkets).to.eql(1); - expect(recipient.purchased.plan.consecutive.gemCapExtra).to.eql(5); - }); - - it('awards perks if plan.perkMonthCount reaches 3 without initialized field', async () => { - expect(recipient.purchased.plan.perkMonthCount).to.eql(-1); - expect(recipient.purchased.plan.consecutive.trinkets).to.eql(0); - expect(recipient.purchased.plan.consecutive.gemCapExtra).to.eql(0); - await api.createSubscription(data); - - expect(recipient.purchased.plan.perkMonthCount).to.eql(0); - expect(recipient.purchased.plan.consecutive.trinkets).to.eql(1); - expect(recipient.purchased.plan.consecutive.gemCapExtra).to.eql(5); - }); - - it('awards perks if plan.perkMonthCount goes over 3', async () => { - recipient.purchased.plan = plan; - recipient.purchased.plan.perkMonthCount = 2; - data.sub.key = 'basic_earned'; - - expect(recipient.purchased.plan.perkMonthCount).to.eql(2); - expect(recipient.purchased.plan.consecutive.trinkets).to.eql(0); - expect(recipient.purchased.plan.consecutive.gemCapExtra).to.eql(0); - await api.createSubscription(data); - - expect(recipient.purchased.plan.perkMonthCount).to.eql(2); - expect(recipient.purchased.plan.consecutive.trinkets).to.eql(1); - expect(recipient.purchased.plan.consecutive.gemCapExtra).to.eql(5); - }); - it('sets plan.customerId to "Gift" if it does not already exist', async () => { expect(recipient.purchased.plan.customerId).to.not.exist; @@ -549,33 +470,6 @@ describe('payments/index', () => { expect(user.purchased.plan.dateCurrentTypeCreated).to.not.eql(initialDate); }); - it('keeps plan.perkMonthCount when changing subscription type', async () => { - await api.createSubscription(data); - user.purchased.plan.perkMonthCount = 2; - await api.createSubscription(data); - expect(user.purchased.plan.perkMonthCount).to.eql(2); - }); - - it('sets plan.perkMonthCount to zero when creating new monthly subscription', async () => { - user.purchased.plan.perkMonthCount = 2; - await api.createSubscription(data); - expect(user.purchased.plan.perkMonthCount).to.eql(0); - }); - - it('sets plan.perkMonthCount to zero when creating new 3 month subscription', async () => { - user.purchased.plan.perkMonthCount = 2; - await api.createSubscription(data); - expect(user.purchased.plan.perkMonthCount).to.eql(0); - }); - - it('updates plan.consecutive.offset when changing subscription type', async () => { - await api.createSubscription(data); - expect(user.purchased.plan.consecutive.offset).to.eql(3); - data.sub.key = 'basic_6mo'; - await api.createSubscription(data); - expect(user.purchased.plan.consecutive.offset).to.eql(6); - }); - it('awards the Royal Purple Jackalope pet', async () => { await api.createSubscription(data); @@ -694,6 +588,7 @@ describe('payments/index', () => { expect(user.purchased.plan.dateCreated).to.eql(created); expect(user.purchased.plan.dateUpdated).to.not.eql(updated); expect(user.purchased.plan.customerId).to.eql('customer-id'); + expect(user.purchased.plan.gemCapExtra).to.eql(26); }); }); @@ -741,55 +636,20 @@ describe('payments/index', () => { }); context('Block subscription perks', () => { - it('adds block months to plan.consecutive.offset', async () => { - await api.createSubscription(data); - - expect(user.purchased.plan.consecutive.offset).to.eql(3); - }); - - it('does not add to plans.consecutive.offset if 1 month subscription', async () => { - data.sub.key = 'basic_earned'; - await api.createSubscription(data); - - expect(user.purchased.plan.consecutive.offset).to.eql(0); - }); - - it('resets plans.consecutive.offset if 1 month subscription', async () => { - user.purchased.plan.consecutive.offset = 1; - await user.save(); - data.sub.key = 'basic_earned'; - await api.createSubscription(data); - - expect(user.purchased.plan.consecutive.offset).to.eql(0); - }); - - it('adds 5 to plan.consecutive.gemCapExtra for 3 month block', async () => { - await api.createSubscription(data); - - expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(5); - }); - - it('adds 10 to plan.consecutive.gemCapExtra for 6 month block', async () => { - data.sub.key = 'basic_6mo'; - await api.createSubscription(data); - - expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(10); - }); - - it('adds 20 to plan.consecutive.gemCapExtra for 12 month block', async () => { + it('adds 26 to plan.consecutive.gemCapExtra for 12 month block', async () => { data.sub.key = 'basic_12mo'; await api.createSubscription(data); - expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(20); + expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(26); }); - it('does not raise plan.consecutive.gemCapExtra higher than 25', async () => { + it('does not raise plan.consecutive.gemCapExtra higher than 26', async () => { data.sub.key = 'basic_12mo'; await api.createSubscription(data); await api.createSubscription(data); - expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(25); + expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(26); }); it('adds a plan.consecutive.trinkets for 3 month block', async () => { @@ -798,20 +658,20 @@ describe('payments/index', () => { expect(user.purchased.plan.consecutive.trinkets).to.eql(1); }); - it('adds 2 plan.consecutive.trinkets for 6 month block', async () => { + it('adds 1 plan.consecutive.trinkets for 6 month block', async () => { data.sub.key = 'basic_6mo'; await api.createSubscription(data); - expect(user.purchased.plan.consecutive.trinkets).to.eql(2); + expect(user.purchased.plan.consecutive.trinkets).to.eql(1); }); - it('adds 4 plan.consecutive.trinkets for 12 month block', async () => { + it('adds 12 plan.consecutive.trinkets for 12 month block', async () => { data.sub.key = 'basic_12mo'; await api.createSubscription(data); - expect(user.purchased.plan.consecutive.trinkets).to.eql(4); + expect(user.purchased.plan.consecutive.trinkets).to.eql(12); }); context('Upgrades subscription', () => { @@ -819,70 +679,38 @@ describe('payments/index', () => { beforeEach(async () => { data.updatedFrom = { logic: 'payDifference' }; }); - it('Adds 10 to plan.consecutive.gemCapExtra from basic_earned to basic_6mo', async () => { - data.sub.key = 'basic_earned'; - expect(user.purchased.plan.planId).to.not.exist; - - await api.createSubscription(data); - - expect(user.purchased.plan.planId).to.eql('basic_earned'); - expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(0); - - data.sub.key = 'basic_6mo'; - data.updatedFrom.key = 'basic_earned'; - await api.createSubscription(data); - expect(user.purchased.plan.planId).to.eql('basic_6mo'); - expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(10); - }); - it('Adds 15 to plan.consecutive.gemCapExtra when upgrading from basic_3mo to basic_12mo', async () => { expect(user.purchased.plan.planId).to.not.exist; await api.createSubscription(data); expect(user.purchased.plan.planId).to.eql('basic_3mo'); - expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(5); + expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(0); data.sub.key = 'basic_12mo'; data.updatedFrom.key = 'basic_3mo'; await api.createSubscription(data); expect(user.purchased.plan.planId).to.eql('basic_12mo'); - expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(20); - }); - - it('Adds 2 to plan.consecutive.trinkets from basic_earned to basic_6mo', async () => { - data.sub.key = 'basic_earned'; - expect(user.purchased.plan.planId).to.not.exist; - - await api.createSubscription(data); - - expect(user.purchased.plan.planId).to.eql('basic_earned'); - expect(user.purchased.plan.consecutive.trinkets).to.eql(0); - - data.sub.key = 'basic_6mo'; - data.updatedFrom.key = 'basic_earned'; - await api.createSubscription(data); - expect(user.purchased.plan.planId).to.eql('basic_6mo'); - expect(user.purchased.plan.consecutive.trinkets).to.eql(2); + expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(26); }); - it('Adds 2 to plan.consecutive.trinkets when upgrading from basic_6mo to basic_12mo', async () => { + it('Adds 11 to plan.consecutive.trinkets when upgrading from basic_6mo to basic_12mo', async () => { data.sub.key = 'basic_6mo'; expect(user.purchased.plan.planId).to.not.exist; await api.createSubscription(data); expect(user.purchased.plan.planId).to.eql('basic_6mo'); - expect(user.purchased.plan.consecutive.trinkets).to.eql(2); + expect(user.purchased.plan.consecutive.trinkets).to.eql(1); data.sub.key = 'basic_12mo'; data.updatedFrom.key = 'basic_6mo'; await api.createSubscription(data); expect(user.purchased.plan.planId).to.eql('basic_12mo'); - expect(user.purchased.plan.consecutive.trinkets).to.eql(4); + expect(user.purchased.plan.consecutive.trinkets).to.eql(12); }); - it('Adds 3 to plan.consecutive.trinkets when upgrading from basic_3mo to basic_12mo', async () => { + it('Adds 11 to plan.consecutive.trinkets when upgrading from basic_3mo to basic_12mo', async () => { expect(user.purchased.plan.planId).to.not.exist; await api.createSubscription(data); @@ -894,7 +722,7 @@ describe('payments/index', () => { data.updatedFrom.key = 'basic_3mo'; await api.createSubscription(data); expect(user.purchased.plan.planId).to.eql('basic_12mo'); - expect(user.purchased.plan.consecutive.trinkets).to.eql(4); + expect(user.purchased.plan.consecutive.trinkets).to.eql(12); }); }); @@ -902,21 +730,6 @@ describe('payments/index', () => { beforeEach(async () => { data.updatedFrom = { logic: 'payFull' }; }); - it('Adds 10 to plan.consecutive.gemCapExtra from basic_earned to basic_6mo', async () => { - data.sub.key = 'basic_earned'; - expect(user.purchased.plan.planId).to.not.exist; - - await api.createSubscription(data); - - expect(user.purchased.plan.planId).to.eql('basic_earned'); - expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(0); - - data.sub.key = 'basic_6mo'; - data.updatedFrom.key = 'basic_earned'; - await api.createSubscription(data); - expect(user.purchased.plan.planId).to.eql('basic_6mo'); - expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(10); - }); it('Adds 20 to plan.consecutive.gemCapExtra when upgrading from basic_3mo to basic_12mo', async () => { expect(user.purchased.plan.planId).to.not.exist; @@ -924,48 +737,32 @@ describe('payments/index', () => { await api.createSubscription(data); expect(user.purchased.plan.planId).to.eql('basic_3mo'); - expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(5); + expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(0); data.sub.key = 'basic_12mo'; data.updatedFrom.key = 'basic_3mo'; await api.createSubscription(data); expect(user.purchased.plan.planId).to.eql('basic_12mo'); - expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(25); + expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(26); }); - it('Adds 2 to plan.consecutive.trinkets from basic_earned to basic_6mo', async () => { - data.sub.key = 'basic_earned'; - expect(user.purchased.plan.planId).to.not.exist; - - await api.createSubscription(data); - - expect(user.purchased.plan.planId).to.eql('basic_earned'); - expect(user.purchased.plan.consecutive.trinkets).to.eql(0); - - data.sub.key = 'basic_6mo'; - data.updatedFrom.key = 'basic_earned'; - await api.createSubscription(data); - expect(user.purchased.plan.planId).to.eql('basic_6mo'); - expect(user.purchased.plan.consecutive.trinkets).to.eql(2); - }); - - it('Adds 4 to plan.consecutive.trinkets when upgrading from basic_6mo to basic_12mo', async () => { + it('Adds 11 to plan.consecutive.trinkets when upgrading from basic_6mo to basic_12mo', async () => { data.sub.key = 'basic_6mo'; expect(user.purchased.plan.planId).to.not.exist; await api.createSubscription(data); expect(user.purchased.plan.planId).to.eql('basic_6mo'); - expect(user.purchased.plan.consecutive.trinkets).to.eql(2); + expect(user.purchased.plan.consecutive.trinkets).to.eql(1); data.sub.key = 'basic_12mo'; data.updatedFrom.key = 'basic_6mo'; await api.createSubscription(data); expect(user.purchased.plan.planId).to.eql('basic_12mo'); - expect(user.purchased.plan.consecutive.trinkets).to.eql(6); + expect(user.purchased.plan.consecutive.trinkets).to.eql(12); }); - it('Adds 4 to plan.consecutive.trinkets when upgrading from basic_3mo to basic_12mo', async () => { + it('Adds 11 to plan.consecutive.trinkets when upgrading from basic_3mo to basic_12mo', async () => { expect(user.purchased.plan.planId).to.not.exist; await api.createSubscription(data); @@ -977,7 +774,7 @@ describe('payments/index', () => { data.updatedFrom.key = 'basic_3mo'; await api.createSubscription(data); expect(user.purchased.plan.planId).to.eql('basic_12mo'); - expect(user.purchased.plan.consecutive.trinkets).to.eql(5); + expect(user.purchased.plan.consecutive.trinkets).to.eql(12); }); }); @@ -988,30 +785,13 @@ describe('payments/index', () => { data.updatedFrom = { logic: 'refundAndRepay' }; }); context('Upgrades within first half of subscription', () => { - it('Adds 10 to plan.consecutive.gemCapExtra from basic_earned to basic_6mo', async () => { - data.sub.key = 'basic_earned'; - expect(user.purchased.plan.planId).to.not.exist; - await api.createSubscription(data); - - expect(user.purchased.plan.planId).to.eql('basic_earned'); - expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(0); - - data.sub.key = 'basic_6mo'; - data.updatedFrom.key = 'basic_earned'; - clock.restore(); - clock = sinon.useFakeTimers(new Date('2022-01-10')); - await api.createSubscription(data); - expect(user.purchased.plan.planId).to.eql('basic_6mo'); - expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(10); - }); - - it('Adds 15 to plan.consecutive.gemCapExtra when upgrading from basic_3mo to basic_12mo', async () => { + it('Adds 26 to plan.consecutive.gemCapExtra when upgrading from basic_3mo to basic_12mo', async () => { expect(user.purchased.plan.planId).to.not.exist; await api.createSubscription(data); expect(user.purchased.plan.planId).to.eql('basic_3mo'); - expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(5); + expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(0); data.sub.key = 'basic_12mo'; data.updatedFrom.key = 'basic_3mo'; @@ -1019,28 +799,10 @@ describe('payments/index', () => { clock = sinon.useFakeTimers(new Date('2022-02-05')); await api.createSubscription(data); expect(user.purchased.plan.planId).to.eql('basic_12mo'); - expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(20); - }); - - it('Adds 2 to plan.consecutive.trinkets from basic_earned to basic_6mo', async () => { - data.sub.key = 'basic_earned'; - expect(user.purchased.plan.planId).to.not.exist; - - await api.createSubscription(data); - - expect(user.purchased.plan.planId).to.eql('basic_earned'); - expect(user.purchased.plan.consecutive.trinkets).to.eql(0); - - data.sub.key = 'basic_6mo'; - data.updatedFrom.key = 'basic_earned'; - clock.restore(); - clock = sinon.useFakeTimers(new Date('2022-01-08')); - await api.createSubscription(data); - expect(user.purchased.plan.planId).to.eql('basic_6mo'); - expect(user.purchased.plan.consecutive.trinkets).to.eql(2); + expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(26); }); - it('Adds 3 to plan.consecutive.trinkets when upgrading from basic_3mo to basic_12mo', async () => { + it('Adds 11 to plan.consecutive.trinkets when upgrading from basic_3mo to basic_12mo', async () => { expect(user.purchased.plan.planId).to.not.exist; await api.createSubscription(data); @@ -1054,17 +816,17 @@ describe('payments/index', () => { clock = sinon.useFakeTimers(new Date('2022-01-31')); await api.createSubscription(data); expect(user.purchased.plan.planId).to.eql('basic_12mo'); - expect(user.purchased.plan.consecutive.trinkets).to.eql(4); + expect(user.purchased.plan.consecutive.trinkets).to.eql(12); }); - it('Adds 2 to plan.consecutive.trinkets when upgrading from basic_6mo to basic_12mo', async () => { + it('Adds 11 to plan.consecutive.trinkets when upgrading from basic_6mo to basic_12mo', async () => { data.sub.key = 'basic_6mo'; expect(user.purchased.plan.planId).to.not.exist; await api.createSubscription(data); expect(user.purchased.plan.planId).to.eql('basic_6mo'); - expect(user.purchased.plan.consecutive.trinkets).to.eql(2); + expect(user.purchased.plan.consecutive.trinkets).to.eql(1); data.sub.key = 'basic_12mo'; data.updatedFrom.key = 'basic_6mo'; @@ -1072,25 +834,7 @@ describe('payments/index', () => { clock = sinon.useFakeTimers(new Date('2022-01-28')); await api.createSubscription(data); expect(user.purchased.plan.planId).to.eql('basic_12mo'); - expect(user.purchased.plan.consecutive.trinkets).to.eql(4); - }); - - it('Adds 2 to plan.consecutive.trinkets from basic_earned to basic_6mo after initial cycle', async () => { - data.sub.key = 'basic_earned'; - expect(user.purchased.plan.planId).to.not.exist; - - await api.createSubscription(data); - - expect(user.purchased.plan.planId).to.eql('basic_earned'); - expect(user.purchased.plan.consecutive.trinkets).to.eql(0); - - data.sub.key = 'basic_6mo'; - data.updatedFrom.key = 'basic_earned'; - clock.restore(); - clock = sinon.useFakeTimers(new Date('2024-01-08')); - await api.createSubscription(data); - expect(user.purchased.plan.planId).to.eql('basic_6mo'); - expect(user.purchased.plan.consecutive.trinkets).to.eql(2); + expect(user.purchased.plan.consecutive.trinkets).to.eql(12); }); it('Adds 2 to plan.consecutive.trinkets when upgrading from basic_6mo to basic_12mo after initial cycle', async () => { @@ -1277,22 +1021,6 @@ describe('payments/index', () => { }); context('Downgrades subscription', () => { - it('does not remove from plan.consecutive.gemCapExtra from basic_6mo to basic_earned', async () => { - data.sub.key = 'basic_6mo'; - expect(user.purchased.plan.planId).to.not.exist; - - await api.createSubscription(data); - - expect(user.purchased.plan.planId).to.eql('basic_6mo'); - expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(10); - - data.sub.key = 'basic_earned'; - data.updatedFrom = { key: 'basic_6mo' }; - await api.createSubscription(data); - expect(user.purchased.plan.planId).to.eql('basic_earned'); - expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(10); - }); - it('does not remove from plan.consecutive.gemCapExtra from basic_12mo to basic_3mo', async () => { expect(user.purchased.plan.planId).to.not.exist; @@ -1300,28 +1028,12 @@ describe('payments/index', () => { await api.createSubscription(data); expect(user.purchased.plan.planId).to.eql('basic_12mo'); - expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(20); + expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(26); data.sub.key = 'basic_3mo'; data.updatedFrom = { key: 'basic_12mo' }; await api.createSubscription(data); - expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(20); - }); - - it('does not remove from plan.consecutive.trinkets from basic_6mo to basic_earned', async () => { - data.sub.key = 'basic_6mo'; - expect(user.purchased.plan.planId).to.not.exist; - - await api.createSubscription(data); - - expect(user.purchased.plan.planId).to.eql('basic_6mo'); - expect(user.purchased.plan.consecutive.trinkets).to.eql(2); - - data.sub.key = 'basic_earned'; - data.updatedFrom = { key: 'basic_6mo' }; - await api.createSubscription(data); - expect(user.purchased.plan.planId).to.eql('basic_earned'); - expect(user.purchased.plan.consecutive.trinkets).to.eql(2); + expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(26); }); it('does not remove from plan.consecutive.trinkets from basic_12mo to basic_3mo', async () => { @@ -1331,12 +1043,12 @@ describe('payments/index', () => { await api.createSubscription(data); expect(user.purchased.plan.planId).to.eql('basic_12mo'); - expect(user.purchased.plan.consecutive.trinkets).to.eql(4); + expect(user.purchased.plan.consecutive.trinkets).to.eql(12); data.sub.key = 'basic_3mo'; data.updatedFrom = { key: 'basic_12mo' }; await api.createSubscription(data); - expect(user.purchased.plan.consecutive.trinkets).to.eql(4); + expect(user.purchased.plan.consecutive.trinkets).to.eql(12); }); }); }); From e097c9c11538513e1a133ebb5a52ad23d02b3927 Mon Sep 17 00:00:00 2001 From: Phillip Thelen Date: Thu, 8 Aug 2024 10:36:50 +0200 Subject: [PATCH 02/21] begin refactoring --- test/api/unit/libs/cron.test.js | 40 ++++++------- test/api/unit/libs/payments/payments.test.js | 37 ++++++------ website/common/script/cron.js | 14 ----- website/server/libs/cron.js | 57 +------------------ website/server/libs/payments/subscriptions.js | 28 ++++----- website/server/models/subscriptionPlan.js | 37 +++--------- website/server/models/transaction.js | 2 +- 7 files changed, 61 insertions(+), 154 deletions(-) diff --git a/test/api/unit/libs/cron.test.js b/test/api/unit/libs/cron.test.js index 53d732b8ad4..71c478563f8 100644 --- a/test/api/unit/libs/cron.test.js +++ b/test/api/unit/libs/cron.test.js @@ -197,16 +197,14 @@ describe('cron', async () => { user.purchased.plan.dateTerminated = moment(new Date()).subtract({ days: 1 }); user.purchased.plan.consecutive.gemCapExtra = 20; user.purchased.plan.consecutive.count = 5; - user.purchased.plan.consecutive.offset = 1; await cron({ user, tasksByType, daysMissed, analytics, }); expect(user.purchased.plan.customerId).to.not.exist; - expect(user.purchased.plan.consecutive.gemCapExtra).to.equal(0); + expect(user.purchased.plan.consecutive.gemCapExtra).to.equal(20); expect(user.purchased.plan.consecutive.count).to.equal(0); - expect(user.purchased.plan.consecutive.offset).to.equal(0); }); describe('for a 1-month recurring subscription', async () => { @@ -229,7 +227,7 @@ describe('cron', async () => { user1.purchased.plan.planId = 'basic'; user1.purchased.plan.consecutive.count = 0; user1.purchased.plan.perkMonthCount = 0; - user1.purchased.plan.consecutive.trinkets = 0; + user1.purchased.plan.consecutive.trinkets = 1; user1.purchased.plan.consecutive.gemCapExtra = 0; }); @@ -256,7 +254,7 @@ describe('cron', async () => { user: user1, tasksByType, daysMissed, analytics, }); expect(user1.purchased.plan.consecutive.count).to.equal(10); - expect(user1.purchased.plan.consecutive.trinkets).to.equal(10); + expect(user1.purchased.plan.consecutive.trinkets).to.equal(11); expect(user1.purchased.plan.consecutive.gemCapExtra).to.equal(20); }); }); @@ -281,7 +279,7 @@ describe('cron', async () => { user3.purchased.plan.perkMonthCount = 0; user3.purchased.plan.consecutive.count = 0; user3.purchased.plan.consecutive.trinkets = 1; - user3.purchased.plan.consecutive.gemCapExtra = 5; + user3.purchased.plan.consecutive.gemCapExtra = 0; }); it('increments consecutive benefits', async () => { @@ -304,7 +302,7 @@ describe('cron', async () => { user: user3, tasksByType, daysMissed, analytics, }); expect(user3.purchased.plan.consecutive.count).to.equal(10); - expect(user3.purchased.plan.consecutive.trinkets).to.equal(10); + expect(user3.purchased.plan.consecutive.trinkets).to.equal(11); expect(user3.purchased.plan.consecutive.gemCapExtra).to.equal(20); }); }); @@ -328,8 +326,8 @@ describe('cron', async () => { user6.purchased.plan.planId = 'google_6mo'; user6.purchased.plan.perkMonthCount = 0; user6.purchased.plan.consecutive.count = 0; - user6.purchased.plan.consecutive.trinkets = 2; - user6.purchased.plan.consecutive.gemCapExtra = 10; + user6.purchased.plan.consecutive.trinkets = 1; + user6.purchased.plan.consecutive.gemCapExtra = 0; }); it('increments benefits', async () => { @@ -362,8 +360,8 @@ describe('cron', async () => { user12.purchased.plan.dateUpdated = moment().toDate(); user12.purchased.plan.planId = 'basic_12mo'; user12.purchased.plan.consecutive.count = 0; - user12.purchased.plan.consecutive.trinkets = 4; - user12.purchased.plan.consecutive.gemCapExtra = 20; + user12.purchased.plan.consecutive.trinkets = 1; + user12.purchased.plan.consecutive.gemCapExtra = 26; it('increments consecutive benefits the month after the second paid period has started', async () => { clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(1, 'months') @@ -373,7 +371,7 @@ describe('cron', async () => { user: user12, tasksByType, daysMissed, analytics, }); expect(user12.purchased.plan.consecutive.count).to.equal(1); - expect(user12.purchased.plan.consecutive.trinkets).to.equal(13); + expect(user12.purchased.plan.consecutive.trinkets).to.equal(2); expect(user12.purchased.plan.consecutive.gemCapExtra).to.equal(26); }); @@ -385,8 +383,8 @@ describe('cron', async () => { user: user12, tasksByType, daysMissed, analytics, }); expect(user12.purchased.plan.consecutive.count).to.equal(10); - expect(user12.purchased.plan.consecutive.trinkets).to.equal(22); - expect(user12.purchased.plan.consecutive.gemCapExtra).to.equal(65); + expect(user12.purchased.plan.consecutive.trinkets).to.equal(11); + expect(user12.purchased.plan.consecutive.gemCapExtra).to.equal(26); }); }); @@ -410,7 +408,7 @@ describe('cron', async () => { user3g.purchased.plan.planId = null; user3g.purchased.plan.consecutive.count = 0; user3g.purchased.plan.consecutive.trinkets = 1; - user3g.purchased.plan.consecutive.gemCapExtra = 5; + user3g.purchased.plan.consecutive.gemCapExtra = 0; it('increments benefits', async () => { clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(1, 'months') @@ -419,10 +417,9 @@ describe('cron', async () => { await cron({ user: user3g, tasksByType, daysMissed, analytics, }); - expect(user3g.purchased.plan.consecutive.count).to.equal(3); - expect(user3g.purchased.plan.consecutive.offset).to.equal(0); - expect(user3g.purchased.plan.consecutive.trinkets).to.equal(1); - expect(user3g.purchased.plan.consecutive.gemCapExtra).to.equal(5); + expect(user3g.purchased.plan.consecutive.count).to.equal(1); + expect(user3g.purchased.plan.consecutive.trinkets).to.equal(2); + expect(user3g.purchased.plan.consecutive.gemCapExtra).to.equal(2); }); it('does not increment consecutive benefits in the month after the gift subscription has ended', async () => { @@ -434,9 +431,8 @@ describe('cron', async () => { }); // subscription has been erased by now expect(user3g.purchased.plan.consecutive.count).to.equal(0); - expect(user3g.purchased.plan.consecutive.offset).to.equal(0); - expect(user3g.purchased.plan.consecutive.trinkets).to.equal(1); - expect(user3g.purchased.plan.consecutive.gemCapExtra).to.equal(0); // erased + expect(user3g.purchased.plan.consecutive.trinkets).to.equal(2); + expect(user3g.purchased.plan.consecutive.gemCapExtra).to.equal(2); }); }); }); diff --git a/test/api/unit/libs/payments/payments.test.js b/test/api/unit/libs/payments/payments.test.js index 5fc08e9f196..62bb67b51db 100644 --- a/test/api/unit/libs/payments/payments.test.js +++ b/test/api/unit/libs/payments/payments.test.js @@ -13,7 +13,7 @@ import { import * as worldState from '../../../../../website/server/libs/worldState'; import { TransactionModel } from '../../../../../website/server/models/transaction'; -describe('payments/index', () => { +describe.only('payments/index', () => { let user; let group; let data; @@ -108,10 +108,6 @@ describe('payments/index', () => { }); it('add a transaction entry to the recipient', async () => { - recipient.purchased.plan = plan; - - expect(recipient.purchased.plan.extraMonths).to.eql(0); - await api.createSubscription(data); expect(recipient.purchased.plan.extraMonths).to.eql(3); @@ -199,13 +195,13 @@ describe('payments/index', () => { it('gives user 1 hourglass if they have no active subscription', async () => { await api.createSubscription(data); - expect(recipient.purchased.plan.trinket).to.eql(1); + expect(recipient.purchased.plan.consecutive.trinkets).to.eql(1); }); - it('does not giec any hourglasses if they have an active subscription', async () => { + it('does not give any hourglasses if they have an active subscription', async () => { recipient.purchased.plan = plan; await api.createSubscription(data); - expect(recipient.purchased.plan.trinket).to.eql(plan.trinket); + expect(recipient.purchased.plan.consecutive.trinkets).to.eql(plan.consecutive.trinkets); }); it('sets plan.dateUpdated if it did exist but the user has cancelled', async () => { @@ -666,6 +662,15 @@ describe('payments/index', () => { expect(user.purchased.plan.consecutive.trinkets).to.eql(1); }); + it('adds 1 plan.consecutive.trinkets for 12 month block if they had promo', async () => { + user.purchased.plan.hourGlassPromoReceived = new Date(); + data.sub.key = 'basic_12mo'; + + await api.createSubscription(data); + + expect(user.purchased.plan.consecutive.trinkets).to.eql(1); + }); + it('adds 12 plan.consecutive.trinkets for 12 month block', async () => { data.sub.key = 'basic_12mo'; @@ -944,7 +949,7 @@ describe('payments/index', () => { expect(user.purchased.plan.consecutive.trinkets).to.eql(6); }); - it('Adds 4 to plan.consecutive.trinkets when upgrading from basic_3mo to basic_12mo', async () => { + it('Adds 11 to plan.consecutive.trinkets when upgrading from basic_3mo to basic_12mo', async () => { expect(user.purchased.plan.planId).to.not.exist; await api.createSubscription(data); @@ -958,17 +963,17 @@ describe('payments/index', () => { clock = sinon.useFakeTimers(new Date('2022-03-03')); await api.createSubscription(data); expect(user.purchased.plan.planId).to.eql('basic_12mo'); - expect(user.purchased.plan.consecutive.trinkets).to.eql(5); + expect(user.purchased.plan.consecutive.trinkets).to.eql(12); }); - it('Adds 2 to plan.consecutive.trinkets from basic_earned to basic_6mo after initial cycle', async () => { + it('Adds 11 to plan.consecutive.trinkets from basic_earned to basic_6mo after initial cycle', async () => { data.sub.key = 'basic_earned'; expect(user.purchased.plan.planId).to.not.exist; await api.createSubscription(data); expect(user.purchased.plan.planId).to.eql('basic_earned'); - expect(user.purchased.plan.consecutive.trinkets).to.eql(0); + expect(user.purchased.plan.consecutive.trinkets).to.eql(1); data.sub.key = 'basic_6mo'; data.updatedFrom.key = 'basic_earned'; @@ -976,17 +981,17 @@ describe('payments/index', () => { clock = sinon.useFakeTimers(new Date('2022-05-28')); await api.createSubscription(data); expect(user.purchased.plan.planId).to.eql('basic_6mo'); - expect(user.purchased.plan.consecutive.trinkets).to.eql(2); + expect(user.purchased.plan.consecutive.trinkets).to.eql(12); }); - it('Adds 4 to plan.consecutive.trinkets when upgrading from basic_6mo to basic_12mo after initial cycle', async () => { + it('Adds 11 to plan.consecutive.trinkets when upgrading from basic_6mo to basic_12mo after initial cycle', async () => { data.sub.key = 'basic_6mo'; expect(user.purchased.plan.planId).to.not.exist; await api.createSubscription(data); expect(user.purchased.plan.planId).to.eql('basic_6mo'); - expect(user.purchased.plan.consecutive.trinkets).to.eql(2); + expect(user.purchased.plan.consecutive.trinkets).to.eql(1); data.sub.key = 'basic_12mo'; data.updatedFrom.key = 'basic_6mo'; @@ -994,7 +999,7 @@ describe('payments/index', () => { clock = sinon.useFakeTimers(new Date('2023-05-28')); await api.createSubscription(data); expect(user.purchased.plan.planId).to.eql('basic_12mo'); - expect(user.purchased.plan.consecutive.trinkets).to.eql(6); + expect(user.purchased.plan.consecutive.trinkets).to.eql(12); }); it('Adds 4 to plan.consecutive.trinkets when upgrading from basic_3mo to basic_12mo after initial cycle', async () => { diff --git a/website/common/script/cron.js b/website/common/script/cron.js index e66cd114e0d..bf76e0e1603 100644 --- a/website/common/script/cron.js +++ b/website/common/script/cron.js @@ -8,7 +8,6 @@ import defaults from 'lodash/defaults'; import invert from 'lodash/invert'; import moment from 'moment'; import 'moment-recur'; -import subscriptionBlocks from './content/subscriptionBlocks'; export const DAY_MAPPING = { 0: 'su', @@ -287,23 +286,10 @@ export function getPlanContext (user, now) { const dateUpdatedMoment = moment(plan.dateUpdated).startOf('month'); const elapsedMonths = moment(subscriptionEndDate).diff(dateUpdatedMoment, 'months'); - const planMonths = subscriptionBlocks[plan.planId] ? subscriptionBlocks[plan.planId].months : 1; - let monthsTillNextHourglass; - if (planMonths > 1) { - monthsTillNextHourglass = Number(plan.consecutive.offset) + 1; - } else { - monthsTillNextHourglass = 3 - plan.perkMonthCount; - } - - const possibleNextHourglassDate = moment(plan.dateUpdated) - .add(monthsTillNextHourglass, 'months'); - return { plan, subscriptionEndDate, dateUpdatedMoment, elapsedMonths, - offset: plan.consecutive.offset, // months until the new hourglass is added - nextHourglassDate: possibleNextHourglassDate, }; } diff --git a/website/server/libs/cron.js b/website/server/libs/cron.js index 39d548de2fc..07a669840cd 100644 --- a/website/server/libs/cron.js +++ b/website/server/libs/cron.js @@ -15,7 +15,6 @@ const { shouldDo, i18n, getPlanContext, - getPlanMonths, } = common; const { scoreTask } = common.ops; const { loginIncentives } = common.content; @@ -67,59 +66,11 @@ async function grantEndOfTheMonthPerks (user, now) { if (elapsedMonths > 0) { plan.dateUpdated = now; - // For every month, inc their "consecutive months" counter. - // Give perks based on consecutive blocks - // If they already got perks for those blocks (eg, 6mo subscription, - // subscription gifts, etc) - then dec the offset until it hits 0 - // Award mystery items revealMysteryItems(user, elapsedMonths); - // 1 for one-month recurring or gift subscriptions; later set to 3 for 3-month recurring, etc. - let planMonthsLength = 1; - - for (let i = 0; i < elapsedMonths; i += 1) { - plan.consecutive.count += 1; - - plan.consecutive.offset -= 1; - // 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) { - planMonthsLength = getPlanMonths(plan); - } - - if (planMonthsLength === 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. - // 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) - plan.consecutive.offset = planMonthsLength - 1; - } - if (!plan.gift && plan.customerId.indexOf('Gift') === -1) { - // Don't process gifted subs here, since they already got their perks. - - // eslint-disable-next-line no-await-in-loop - await plan.incrementPerkCounterAndReward(user._id, planMonthsLength); - } - } - } + plan.consecutive.count += elapsedMonths; + await plan.rewardPerks(user._id, elapsedMonths); } } @@ -135,8 +86,6 @@ function removeTerminatedSubscription (user) { _.merge(plan.consecutive, { count: 0, - offset: 0, - gemCapExtra: 0, }); user.markModified('purchased.plan'); @@ -283,8 +232,6 @@ export async function cron (options = {}) { if (user.isSubscribed()) { await grantEndOfTheMonthPerks(user, now); - } if (!user.isSubscribed() && user.purchased.plan.perkMonthCount > 0) { - user.purchased.plan.perkMonthCount = 0; } const { plan } = user.purchased; diff --git a/website/server/libs/payments/subscriptions.js b/website/server/libs/payments/subscriptions.js index 33dd3421e76..6223cc473ea 100644 --- a/website/server/libs/payments/subscriptions.js +++ b/website/server/libs/payments/subscriptions.js @@ -249,24 +249,7 @@ async function createSubscription (data) { itemPurchased, purchaseType, emailType, - isNewSubscription, } = await prepareSubscriptionValues(data); - - // Block sub perks - if (months > 1 && (!data.gift || !isNewSubscription)) { - if (!data.gift && !groupId) { - plan.consecutive.offset = block.months; - } - } else if (months === 1) { - plan.consecutive.offset = 0; - } - if (months > 1 || data.gift) { - await plan.incrementPerkCounterAndReward(recipient._id, months); - } else { - // Make sure the perkMonthCount field is initialized. - await plan.incrementPerkCounterAndReward(recipient._id, 0); - } - if (recipient !== group) { recipient.items.pets['Jackalope-RoyalPurple'] = 5; recipient.markModified('items.pets'); @@ -278,6 +261,17 @@ async function createSubscription (data) { txnEmail(data.user, emailType); } + if (months === 12) { + plan.consecutive.gemCapExtra = 26; + } + + if (months === 12 && autoRenews && !recipient.purchased.plan.hourglassPromoReceived) { + recipient.purchased.plan.hourglassPromoReceived = new Date(); + await plan.updateHourglasses(recipient._id, 12, '12_month_subscription'); + } else if (!data.gift || (data.gift && !recipient.isSubscribed())) { + await plan.updateHourglasses(recipient._id, 1, 'subscribed'); + } + if (!group && !data.promo) data.user.purchased.txnCount += 1; if (!data.promo) { diff --git a/website/server/models/subscriptionPlan.js b/website/server/models/subscriptionPlan.js index a6c540a10cf..ed1e110d1e2 100644 --- a/website/server/models/subscriptionPlan.js +++ b/website/server/models/subscriptionPlan.js @@ -3,9 +3,6 @@ import validator from 'validator'; import baseModel from '../libs/baseModel'; import { TransactionModel as Transaction } from './transaction'; -// multi-month subscriptions are for multiples of 3 months -const SUBSCRIPTION_BASIC_BLOCK_LENGTH = 3; - export const schema = new mongoose.Schema({ planId: String, subscriptionId: String, @@ -18,7 +15,6 @@ export const schema = new mongoose.Schema({ dateUpdated: Date, dateCurrentTypeCreated: Date, extraMonths: { $type: Number, default: 0 }, - perkMonthCount: { $type: Number, default: -1 }, gemsBought: { $type: Number, default: 0 }, mysteryItems: { $type: Array, default: () => [] }, lastReminderDate: Date, // indicates the last time a subscription reminder was sent @@ -28,6 +24,7 @@ export const schema = new mongoose.Schema({ // indicates when the queue server should process this subscription again. nextPaymentProcessing: Date, nextBillingDate: Date, // Next time google will bill this user. + hourglassPromoReceived: Date, consecutive: { count: { $type: Number, default: 0 }, // when gifted subs, offset++ for each month. offset-- each new-month (cron). @@ -50,36 +47,18 @@ schema.plugin(baseModel, { _id: false, }); -schema.methods.incrementPerkCounterAndReward = async function incrementPerkCounterAndReward +schema.methods.rewardPerks = async function rewardPerks (userID, adding) { - let addingNumber = adding; + let perks = adding; if (typeof adding === 'string' || adding instanceof String) { - addingNumber = parseInt(adding, 10); - } - const isSingleMonthPlan = this.planId === 'basic_earned' || this.planId === 'group_plan_auto' || this.planId === 'group_monthly'; - // if perkMonthCount wasn't used before, initialize it. - if (this.perkMonthCount === undefined || this.perkMonthCount === -1) { - if (isSingleMonthPlan && this.consecutive.count > 0) { - this.perkMonthCount = (this.consecutive.count - 1) % SUBSCRIPTION_BASIC_BLOCK_LENGTH; - } else { - this.perkMonthCount = 0; - } - } else if (isSingleMonthPlan) { - const expectedPerkMonthCount = (this.consecutive.count - 1) % SUBSCRIPTION_BASIC_BLOCK_LENGTH; - if (this.perkMonthCount === (expectedPerkMonthCount - 1)) { - // User was affected by a bug that makes their perkMonthCount off by one - this.perkMonthCount += 1; - } + perks = parseInt(adding, 10); } - this.perkMonthCount += addingNumber; - const perks = Math.floor(this.perkMonthCount / 3); if (perks > 0) { - this.consecutive.gemCapExtra += 5 * perks; // 5 extra Gems every 3 months - // cap it at 50 (hard 25 limit + extra 25) - if (this.consecutive.gemCapExtra > 25) this.consecutive.gemCapExtra = 25; - this.perkMonthCount -= (perks * 3); - // one Hourglass every 3 months + this.consecutive.gemCapExtra += 2 * perks; // 2 extra Gems every month + // cap it at 50 (hard 24 limit + extra 26) + if (this.consecutive.gemCapExtra > 26) this.consecutive.gemCapExtra = 26; + // one Hourglass every month await this.updateHourglasses(userID, perks, 'subscription_perks'); // eslint-disable-line no-await-in-loop } }; diff --git a/website/server/models/transaction.js b/website/server/models/transaction.js index 608ddcae773..d97111588d4 100644 --- a/website/server/models/transaction.js +++ b/website/server/models/transaction.js @@ -5,7 +5,7 @@ import baseModel from '../libs/baseModel'; const { Schema } = mongoose; export const currencies = ['gems', 'hourglasses']; -export const transactionTypes = ['buy_money', 'buy_gold', 'spend', 'gift_send', 'gifted_with_money', 'gift_receive', 'debug', 'create_challenge', 'create_bank_challenge', 'create_guild', 'change_class', 'rebirth', 'release_pets', 'release_mounts', 'reroll', 'contribution', 'subscription_perks', 'admin_update_balance', 'admin_update_hourglasses']; +export const transactionTypes = ['buy_money', 'buy_gold', 'spend', 'gift_send', 'gifted_with_money', 'gift_receive', 'debug', 'create_challenge', 'create_bank_challenge', 'create_guild', 'change_class', 'rebirth', 'release_pets', 'release_mounts', 'reroll', 'contribution', 'subscription_perks', 'subscribed', '12_month_subscription', 'admin_update_balance', 'admin_update_hourglasses']; export const schema = new Schema({ currency: { $type: String, enum: currencies, required: true }, From e2eb895546884fc405fa41702d1ea48dcfc150b3 Mon Sep 17 00:00:00 2001 From: Phillip Thelen Date: Wed, 7 Aug 2024 05:41:18 -0400 Subject: [PATCH 03/21] update cron tests --- test/common/libs/cron.test.js | 51 ++++++----------------------------- 1 file changed, 8 insertions(+), 43 deletions(-) diff --git a/test/common/libs/cron.test.js b/test/common/libs/cron.test.js index e8be92fceb5..edb5014b6c3 100644 --- a/test/common/libs/cron.test.js +++ b/test/common/libs/cron.test.js @@ -182,9 +182,7 @@ describe('cron utility functions', () => { }); }); - describe('getPlanContext', () => { - const now = new Date(2022, 5, 1); - + describe.only('getPlanContext', () => { function baseUserData (count, offset, planId) { return { purchased: { @@ -213,52 +211,19 @@ describe('cron utility functions', () => { }; } - it('monthly plan, next date in 3 months', () => { + it('elapsedMonths is 0 if its the same month', () => { const user = baseUserData(60, 0, 'group_plan_auto'); - user.purchased.plan.perkMonthCount = 0; - - const planContext = getPlanContext(user, now); - - expect(planContext.nextHourglassDate) - .to.be.sameMoment('2022-08-10T02:00:00.144Z'); - }); - it('monthly plan, next date in 1 month', () => { - const user = baseUserData(62, 0, 'group_plan_auto'); - user.purchased.plan.perkMonthCount = 2; - - const planContext = getPlanContext(user, now); - - expect(planContext.nextHourglassDate) - .to.be.sameMoment('2022-06-10T02:00:00.144Z'); + const planContext = getPlanContext(user, new Date(2022, 4, 20)); + expect(planContext.elapsedMonths).to.equal(0); }); - it('multi-month plan, no offset', () => { - const user = baseUserData(60, 0, 'basic_3mo'); - - const planContext = getPlanContext(user, now); - - expect(planContext.nextHourglassDate) - .to.be.sameMoment('2022-06-10T02:00:00.144Z'); - }); - - it('multi-month plan with offset', () => { - const user = baseUserData(60, 1, 'basic_3mo'); - - const planContext = getPlanContext(user, now); - - expect(planContext.nextHourglassDate) - .to.be.sameMoment('2022-07-10T02:00:00.144Z'); - }); - - it('multi-month plan with perk count', () => { - const user = baseUserData(60, 1, 'basic_3mo'); - user.purchased.plan.perkMonthCount = 2; + it('elapsedMonths is 1 after one month', () => { + const user = baseUserData(60, 0, 'group_plan_auto'); - const planContext = getPlanContext(user, now); + const planContext = getPlanContext(user, new Date(2022, 5, 11)); - expect(planContext.nextHourglassDate) - .to.be.sameMoment('2022-07-10T02:00:00.144Z'); + expect(planContext.elapsedMonths).to.equal(1); }); }); }); From d8eaf0c983d463278157d735cdf2423c41b1e8d2 Mon Sep 17 00:00:00 2001 From: Phillip Thelen Date: Fri, 9 Aug 2024 11:37:44 +0200 Subject: [PATCH 04/21] cleanup --- test/api/unit/libs/bug-report.test.js | 1 - .../group-plans/group-payments-create.test.js | 2 +- test/api/unit/libs/payments/payments.test.js | 3 +- test/common/libs/cron.test.js | 2 +- .../user-support/subscriptionAndPerks.vue | 41 +++---------------- .../src/components/group-plans/billing.vue | 4 +- .../src/components/settings/subscription.vue | 6 +-- website/server/controllers/api-v3/hall.js | 6 --- website/server/libs/bug-report.js | 1 - website/server/libs/payments/subscriptions.js | 4 -- 10 files changed, 12 insertions(+), 58 deletions(-) diff --git a/test/api/unit/libs/bug-report.test.js b/test/api/unit/libs/bug-report.test.js index 58eefca3e65..5cb33d39b49 100644 --- a/test/api/unit/libs/bug-report.test.js +++ b/test/api/unit/libs/bug-report.test.js @@ -44,7 +44,6 @@ describe('bug-report', () => { USER_HOURGLASSES: 0, USER_ID: userId, USER_LEVEL: 1, - USER_OFFSET_MONTHS: 0, USER_PAYMENT_PLATFORM: undefined, USER_SUBSCRIPTION: undefined, USER_TIMEZONE_OFFSET: 0, diff --git a/test/api/unit/libs/payments/group-plans/group-payments-create.test.js b/test/api/unit/libs/payments/group-plans/group-payments-create.test.js index 383d7dfe6f3..17ff154a0a0 100644 --- a/test/api/unit/libs/payments/group-plans/group-payments-create.test.js +++ b/test/api/unit/libs/payments/group-plans/group-payments-create.test.js @@ -715,7 +715,7 @@ describe('Purchasing a group plan for group', () => { const mysteryItem = { title: 'item' }; const mysteryItems = [mysteryItem]; const consecutive = { - trinkets: 3, + trinkets: 4, gemCapExtra: 20, offset: 1, count: 13, diff --git a/test/api/unit/libs/payments/payments.test.js b/test/api/unit/libs/payments/payments.test.js index 62bb67b51db..57983318c05 100644 --- a/test/api/unit/libs/payments/payments.test.js +++ b/test/api/unit/libs/payments/payments.test.js @@ -13,7 +13,7 @@ import { import * as worldState from '../../../../../website/server/libs/worldState'; import { TransactionModel } from '../../../../../website/server/models/transaction'; -describe.only('payments/index', () => { +describe('payments/index', () => { let user; let group; let data; @@ -428,7 +428,6 @@ describe.only('payments/index', () => { expect(user.purchased.plan.customerId).to.eql('customer-id'); expect(user.purchased.plan.dateUpdated).to.exist; expect(user.purchased.plan.gemsBought).to.eql(0); - expect(user.purchased.plan.perkMonthCount).to.eql(0); expect(user.purchased.plan.paymentMethod).to.eql('Payment Method'); expect(user.purchased.plan.extraMonths).to.eql(0); expect(user.purchased.plan.dateTerminated).to.eql(null); diff --git a/test/common/libs/cron.test.js b/test/common/libs/cron.test.js index edb5014b6c3..0eb7e640c25 100644 --- a/test/common/libs/cron.test.js +++ b/test/common/libs/cron.test.js @@ -182,7 +182,7 @@ describe('cron utility functions', () => { }); }); - describe.only('getPlanContext', () => { + describe('getPlanContext', () => { function baseUserData (count, offset, planId) { return { purchased: { diff --git a/website/client/src/components/admin-panel/user-support/subscriptionAndPerks.vue b/website/client/src/components/admin-panel/user-support/subscriptionAndPerks.vue index 2d3fd5679c3..770a9dd3e4b 100644 --- a/website/client/src/components/admin-panel/user-support/subscriptionAndPerks.vue +++ b/website/client/src/components/admin-panel/user-support/subscriptionAndPerks.vue @@ -103,43 +103,12 @@ > -
- -
- -
+
+ Next Mystic Hourglass: + {{ nextHourglassDate }}
-
- -
- -
-
-
- - {{ nextHourglassDate }} -
-
-
-
- Next Mystic Hourglass: - {{ nextHourglassDate }} +
+ + {{ nextHourglassDate }}
-
-