Group plans subs to all (#8394)
* Added subscriptions to all members when group subs * Added unsub when group cancels * Give user a subscription when they join a subbed group * Removed subscription when user leaves or is removed from group * Fixed linting issues: * Added tests for users with a subscription being upgraded to group plan * Added tests for checking if existing recurring user sub gets updated during group plan. Added better merging for plans * Added test for existing gift subscriptions * Added additional months to user when they have an existing recurring subscription and get upgraded to group sub * Adds test for user who has cancelled with date termined in the future * Added test to ensure date termined is reset * Added tests for extra months carrying over * Added test for gems bought field * Add tests to for fields that should remain when upgrading * Added test for all payment methods * Added prevention for when a user joins a second group plan * Fixed subscribing tests * Separated group plan payment tests * Added prevention of editing a user with a unlimited sub * Add tests to ensure group keeps plan if they are in two and leave one * Ensured users with two group plans do not get cancelled when on group plan is cancelled * Ensured users without group sub are untouched when group cancels * Fixed lint issues * Added new emails * Added fix for cron tests * Add restore to stubbed methods * Ensured cancelled group subscriptions are updated * Changed group plan exist check to check for date terminated * Updated you cannont delete active group message * Removed description requirement * Added upgrade group plan for Amazon payments * Fixed lint issues * Fixed broken tests * Fixed user delete tests * Fixed function calls * Hid cancel button if user has group plan * Hide difficulty from rewards * Prevented add user functions to be called when group plan is cancelled * Fixed merge issue * Correctly displayed group price * Added message when you are about to join canclled group plan * Fixed linting issues * Updated tests to have no redirect to homes * Allowed leaving a group with a canceld subscription * Fixed spelling issues * Prevented user from changing leader with active sub * Added payment details title to replace subscription title * Ensured we do not count leader when displaying upcoming cost * Prevented party tasks from being displayed twice * Prevented cancelling and already cancelled sub * Fixed styles of subscriptions * Added more specific mystery item tests * Fixed test to refer to leader * Extended test range to account for short months * Fixed merge conflicts * Updated yarn file * Added missing locales * Trigger notification * Removed yarn * Fixed locales * Fixed scope mispelling * Fixed line endings * Removed extra advanced options from rewards * Prevent group leader from leaving an active group plan * Fixed issue with extra months applied to cancelled group plan * Ensured member count is calculated when updatedGroupPlan * Updated amazon payment method constant name * Added comment to cancel sub user method * Fixed smantic issues * Added unite test for user isSubscribed and hasNotCancelled * Add tests for isSubscribed and hasNotCanceled * Changed default days remaining to 2 days for group plans * Fixed logic with adding canceled notice to group invite
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
import moment from 'moment';
|
||||
import cc from 'coupon-code';
|
||||
import uuid from 'uuid';
|
||||
|
||||
import {
|
||||
generateGroup,
|
||||
} from '../../../../helpers/api-unit.helper.js';
|
||||
import { model as User } from '../../../../../website/server/models/user';
|
||||
import { model as Group } from '../../../../../website/server/models/group';
|
||||
import { model as Coupon } from '../../../../../website/server/models/coupon';
|
||||
import amzLib from '../../../../../website/server/libs/amazonPayments';
|
||||
import payments from '../../../../../website/server/libs/payments';
|
||||
@@ -105,7 +107,7 @@ describe('Amazon Payments', () => {
|
||||
expect(paymentBuyGemsStub).to.be.calledOnce;
|
||||
expect(paymentBuyGemsStub).to.be.calledWith({
|
||||
user,
|
||||
paymentMethod: amzLib.constants.PAYMENT_METHOD_AMAZON,
|
||||
paymentMethod: amzLib.constants.PAYMENT_METHOD,
|
||||
headers,
|
||||
});
|
||||
expectAmazonStubs();
|
||||
@@ -128,7 +130,7 @@ describe('Amazon Payments', () => {
|
||||
expect(paymentBuyGemsStub).to.be.calledOnce;
|
||||
expect(paymentBuyGemsStub).to.be.calledWith({
|
||||
user,
|
||||
paymentMethod: amzLib.constants.PAYMENT_METHOD_AMAZON_GIFT,
|
||||
paymentMethod: amzLib.constants.PAYMENT_METHOD_GIFT,
|
||||
headers,
|
||||
gift,
|
||||
});
|
||||
@@ -153,7 +155,7 @@ describe('Amazon Payments', () => {
|
||||
expect(paymentCreateSubscritionStub).to.be.calledOnce;
|
||||
expect(paymentCreateSubscritionStub).to.be.calledWith({
|
||||
user,
|
||||
paymentMethod: amzLib.constants.PAYMENT_METHOD_AMAZON_GIFT,
|
||||
paymentMethod: amzLib.constants.PAYMENT_METHOD_GIFT,
|
||||
headers,
|
||||
gift,
|
||||
});
|
||||
@@ -316,7 +318,7 @@ describe('Amazon Payments', () => {
|
||||
expect(createSubSpy).to.be.calledWith({
|
||||
user,
|
||||
customerId: billingAgreementId,
|
||||
paymentMethod: amzLib.constants.PAYMENT_METHOD_AMAZON,
|
||||
paymentMethod: amzLib.constants.PAYMENT_METHOD,
|
||||
sub,
|
||||
headers,
|
||||
groupId,
|
||||
@@ -375,7 +377,7 @@ describe('Amazon Payments', () => {
|
||||
expect(createSubSpy).to.be.calledWith({
|
||||
user,
|
||||
customerId: billingAgreementId,
|
||||
paymentMethod: amzLib.constants.PAYMENT_METHOD_AMAZON,
|
||||
paymentMethod: amzLib.constants.PAYMENT_METHOD,
|
||||
sub,
|
||||
headers,
|
||||
groupId,
|
||||
@@ -455,7 +457,7 @@ describe('Amazon Payments', () => {
|
||||
user,
|
||||
groupId: undefined,
|
||||
nextBill: moment(user.purchased.plan.lastBillingDate).add({ days: subscriptionLength }),
|
||||
paymentMethod: amzLib.constants.PAYMENT_METHOD_AMAZON,
|
||||
paymentMethod: amzLib.constants.PAYMENT_METHOD,
|
||||
headers,
|
||||
});
|
||||
expectAmazonStubs();
|
||||
@@ -485,7 +487,7 @@ describe('Amazon Payments', () => {
|
||||
user,
|
||||
groupId: undefined,
|
||||
nextBill: moment(user.purchased.plan.lastBillingDate).add({ days: subscriptionLength }),
|
||||
paymentMethod: amzLib.constants.PAYMENT_METHOD_AMAZON,
|
||||
paymentMethod: amzLib.constants.PAYMENT_METHOD,
|
||||
headers,
|
||||
});
|
||||
amzLib.closeBillingAgreement.restore();
|
||||
@@ -523,7 +525,7 @@ describe('Amazon Payments', () => {
|
||||
user,
|
||||
groupId: group._id,
|
||||
nextBill: moment(group.purchased.plan.lastBillingDate).add({ days: subscriptionLength }),
|
||||
paymentMethod: amzLib.constants.PAYMENT_METHOD_AMAZON,
|
||||
paymentMethod: amzLib.constants.PAYMENT_METHOD,
|
||||
headers,
|
||||
});
|
||||
expectAmazonStubs();
|
||||
@@ -553,10 +555,84 @@ describe('Amazon Payments', () => {
|
||||
user,
|
||||
groupId: group._id,
|
||||
nextBill: moment(group.purchased.plan.lastBillingDate).add({ days: subscriptionLength }),
|
||||
paymentMethod: amzLib.constants.PAYMENT_METHOD_AMAZON,
|
||||
paymentMethod: amzLib.constants.PAYMENT_METHOD,
|
||||
headers,
|
||||
});
|
||||
amzLib.closeBillingAgreement.restore();
|
||||
});
|
||||
});
|
||||
|
||||
describe('#upgradeGroupPlan', () => {
|
||||
let spy, data, user, group, uuidString;
|
||||
|
||||
beforeEach(async function () {
|
||||
user = new User();
|
||||
user.profile.name = 'sender';
|
||||
|
||||
data = {
|
||||
user,
|
||||
sub: {
|
||||
key: 'basic_3mo', // @TODO: Validate that this is group
|
||||
},
|
||||
customerId: 'customer-id',
|
||||
paymentMethod: 'Payment Method',
|
||||
headers: {
|
||||
'x-client': 'habitica-web',
|
||||
'user-agent': '',
|
||||
},
|
||||
};
|
||||
|
||||
group = generateGroup({
|
||||
name: 'test group',
|
||||
type: 'guild',
|
||||
privacy: 'public',
|
||||
leader: user._id,
|
||||
});
|
||||
await group.save();
|
||||
|
||||
spy = sinon.stub(amzLib, 'authorizeOnBillingAgreement');
|
||||
spy.returnsPromise().resolves([]);
|
||||
|
||||
uuidString = 'uuid-v4';
|
||||
sinon.stub(uuid, 'v4').returns(uuidString);
|
||||
|
||||
data.groupId = group._id;
|
||||
data.sub.quantity = 3;
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
sinon.restore(amzLib.authorizeOnBillingAgreement);
|
||||
uuid.v4.restore();
|
||||
});
|
||||
|
||||
it('charges for a new member', async () => {
|
||||
data.paymentMethod = amzLib.constants.PAYMENT_METHOD;
|
||||
await payments.createSubscription(data);
|
||||
|
||||
let updatedGroup = await Group.findById(group._id).exec();
|
||||
|
||||
updatedGroup.memberCount += 1;
|
||||
await updatedGroup.save();
|
||||
|
||||
await amzLib.chargeForAdditionalGroupMember(updatedGroup);
|
||||
|
||||
expect(spy.calledOnce).to.be.true;
|
||||
expect(spy).to.be.calledWith({
|
||||
AmazonBillingAgreementId: updatedGroup.purchased.plan.customerId,
|
||||
AuthorizationReferenceId: uuidString.substring(0, 32),
|
||||
AuthorizationAmount: {
|
||||
CurrencyCode: amzLib.constants.CURRENCY_CODE,
|
||||
Amount: 3,
|
||||
},
|
||||
SellerAuthorizationNote: amzLib.constants.SELLER_NOTE_GROUP_NEW_MEMBER,
|
||||
TransactionTimeout: 0,
|
||||
CaptureNow: true,
|
||||
SellerNote: amzLib.constants.SELLER_NOTE_GROUP_NEW_MEMBER,
|
||||
SellerOrderAttributes: {
|
||||
SellerOrderId: uuidString,
|
||||
StoreName: amzLib.constants.STORE_NAME,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -134,7 +134,10 @@ describe('cron', () => {
|
||||
user.purchased.plan.dateUpdated = moment().subtract(6, 'months').toDate();
|
||||
user.purchased.plan.dateTerminated = moment().subtract(3, 'months').toDate();
|
||||
user.purchased.plan.consecutive.count = 5;
|
||||
user.purchased.plan.consecutive.trinkets = 1;
|
||||
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.equal(1);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,22 +1,18 @@
|
||||
import moment from 'moment';
|
||||
|
||||
import * as sender from '../../../../../website/server/libs/email';
|
||||
import * as api from '../../../../../website/server/libs/payments';
|
||||
import analytics from '../../../../../website/server/libs/analyticsService';
|
||||
import notifications from '../../../../../website/server/libs/pushNotifications';
|
||||
import { model as User } from '../../../../../website/server/models/user';
|
||||
import { model as Group } from '../../../../../website/server/models/group';
|
||||
import stripeModule from 'stripe';
|
||||
import moment from 'moment';
|
||||
import { translate as t } from '../../../../helpers/api-v3-integration.helper';
|
||||
import {
|
||||
generateGroup,
|
||||
} from '../../../../helpers/api-unit.helper.js';
|
||||
import i18n from '../../../../../website/common/script/i18n';
|
||||
|
||||
describe('payments/index', () => {
|
||||
let user, group, data, plan;
|
||||
|
||||
let stripe = stripeModule('test');
|
||||
|
||||
beforeEach(async () => {
|
||||
user = new User();
|
||||
user.profile.name = 'sender';
|
||||
@@ -319,53 +315,6 @@ describe('payments/index', () => {
|
||||
});
|
||||
});
|
||||
|
||||
context('Purchasing a subscription for group', () => {
|
||||
it('creates a subscription', async () => {
|
||||
expect(group.purchased.plan.planId).to.not.exist;
|
||||
data.groupId = group._id;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedGroup = await Group.findById(group._id).exec();
|
||||
|
||||
expect(updatedGroup.purchased.plan.planId).to.eql('basic_3mo');
|
||||
expect(updatedGroup.purchased.plan.customerId).to.eql('customer-id');
|
||||
expect(updatedGroup.purchased.plan.dateUpdated).to.exist;
|
||||
expect(updatedGroup.purchased.plan.gemsBought).to.eql(0);
|
||||
expect(updatedGroup.purchased.plan.paymentMethod).to.eql('Payment Method');
|
||||
expect(updatedGroup.purchased.plan.extraMonths).to.eql(0);
|
||||
expect(updatedGroup.purchased.plan.dateTerminated).to.eql(null);
|
||||
expect(updatedGroup.purchased.plan.lastBillingDate).to.not.exist;
|
||||
expect(updatedGroup.purchased.plan.dateCreated).to.exist;
|
||||
});
|
||||
|
||||
it('sets extraMonths if plan has dateTerminated date', async () => {
|
||||
group.purchased.plan = plan;
|
||||
group.purchased.plan.dateTerminated = moment(new Date()).add(2, 'months');
|
||||
await group.save();
|
||||
expect(group.purchased.plan.extraMonths).to.eql(0);
|
||||
data.groupId = group._id;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedGroup = await Group.findById(group._id).exec();
|
||||
expect(updatedGroup.purchased.plan.extraMonths).to.within(1.9, 2);
|
||||
});
|
||||
|
||||
it('does not set negative extraMonths if plan has past dateTerminated date', async () => {
|
||||
group.purchased.plan = plan;
|
||||
group.purchased.plan.dateTerminated = moment(new Date()).subtract(2, 'months');
|
||||
await group.save();
|
||||
expect(group.purchased.plan.extraMonths).to.eql(0);
|
||||
data.groupId = group._id;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedGroup = await Group.findById(group._id).exec();
|
||||
expect(updatedGroup.purchased.plan.extraMonths).to.eql(0);
|
||||
});
|
||||
});
|
||||
|
||||
context('Block subscription perks', () => {
|
||||
it('adds block months to plan.consecutive.offset', async () => {
|
||||
await api.createSubscription(data);
|
||||
@@ -558,112 +507,6 @@ describe('payments/index', () => {
|
||||
expect(sender.sendTxn).to.be.calledWith(user, 'cancel-subscription');
|
||||
});
|
||||
});
|
||||
|
||||
context('Canceling a subscription for group', () => {
|
||||
it('adds a month termination date by default', async () => {
|
||||
data.groupId = group._id;
|
||||
await api.cancelSubscription(data);
|
||||
|
||||
let now = new Date();
|
||||
let updatedGroup = await Group.findById(group._id).exec();
|
||||
let daysTillTermination = moment(updatedGroup.purchased.plan.dateTerminated).diff(now, 'days');
|
||||
|
||||
expect(daysTillTermination).to.be.within(29, 30); // 1 month +/- 1 days
|
||||
});
|
||||
|
||||
it('adds extraMonths to dateTerminated value', async () => {
|
||||
group.purchased.plan.extraMonths = 2;
|
||||
await group.save();
|
||||
data.groupId = group._id;
|
||||
|
||||
await api.cancelSubscription(data);
|
||||
|
||||
let now = new Date();
|
||||
let updatedGroup = await Group.findById(group._id).exec();
|
||||
let daysTillTermination = moment(updatedGroup.purchased.plan.dateTerminated).diff(now, 'days');
|
||||
|
||||
expect(daysTillTermination).to.be.within(89, 90); // 3 months +/- 1 days
|
||||
});
|
||||
|
||||
it('handles extra month fractions', async () => {
|
||||
group.purchased.plan.extraMonths = 0.3;
|
||||
await group.save();
|
||||
data.groupId = group._id;
|
||||
|
||||
await api.cancelSubscription(data);
|
||||
|
||||
let now = new Date();
|
||||
let updatedGroup = await Group.findById(group._id).exec();
|
||||
let daysTillTermination = moment(updatedGroup.purchased.plan.dateTerminated).diff(now, 'days');
|
||||
|
||||
expect(daysTillTermination).to.be.within(38, 39); // should be about 1 month + 1/3 month
|
||||
});
|
||||
|
||||
it('terminates at next billing date if it exists', async () => {
|
||||
data.nextBill = moment().add({ days: 15 });
|
||||
data.groupId = group._id;
|
||||
|
||||
await api.cancelSubscription(data);
|
||||
|
||||
let now = new Date();
|
||||
let updatedGroup = await Group.findById(group._id).exec();
|
||||
let daysTillTermination = moment(updatedGroup.purchased.plan.dateTerminated).diff(now, 'days');
|
||||
|
||||
expect(daysTillTermination).to.be.within(13, 15);
|
||||
});
|
||||
|
||||
it('resets plan.extraMonths', async () => {
|
||||
group.purchased.plan.extraMonths = 5;
|
||||
await group.save();
|
||||
data.groupId = group._id;
|
||||
|
||||
await api.cancelSubscription(data);
|
||||
|
||||
let updatedGroup = await Group.findById(group._id).exec();
|
||||
expect(updatedGroup.purchased.plan.extraMonths).to.eql(0);
|
||||
});
|
||||
|
||||
it('sends an email', async () => {
|
||||
data.groupId = group._id;
|
||||
await api.cancelSubscription(data);
|
||||
|
||||
expect(sender.sendTxn).to.be.calledOnce;
|
||||
expect(sender.sendTxn).to.be.calledWith(user, 'group-cancel-subscription');
|
||||
});
|
||||
|
||||
it('prevents non group leader from manging subscription', async () => {
|
||||
let groupMember = new User();
|
||||
data.user = groupMember;
|
||||
data.groupId = group._id;
|
||||
|
||||
await expect(api.cancelSubscription(data))
|
||||
.eventually.be.rejected.and.to.eql({
|
||||
httpCode: 401,
|
||||
message: i18n.t('onlyGroupLeaderCanManageSubscription'),
|
||||
name: 'NotAuthorized',
|
||||
});
|
||||
});
|
||||
|
||||
it('allows old group leader to cancel if they created the subscription', async () => {
|
||||
data.groupId = group._id;
|
||||
data.sub = {
|
||||
key: 'group_monthly',
|
||||
};
|
||||
data.paymentMethod = 'Payment Method';
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedGroup = await Group.findById(group._id).exec();
|
||||
let newLeader = new User();
|
||||
updatedGroup.leader = newLeader._id;
|
||||
await updatedGroup.save();
|
||||
|
||||
await api.cancelSubscription(data);
|
||||
|
||||
updatedGroup = await Group.findById(group._id).exec();
|
||||
|
||||
expect(updatedGroup.purchased.plan.dateTerminated).to.exist;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#buyGems', () => {
|
||||
@@ -771,49 +614,24 @@ describe('payments/index', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('#upgradeGroupPlan', () => {
|
||||
let spy;
|
||||
|
||||
beforeEach(function () {
|
||||
spy = sinon.stub(stripe.subscriptions, 'update');
|
||||
spy.returnsPromise().resolves([]);
|
||||
describe('addSubToGroupUser', () => {
|
||||
it('adds a group subscription to a new user', async () => {
|
||||
expect(group.purchased.plan.planId).to.not.exist;
|
||||
data.groupId = group._id;
|
||||
data.sub.quantity = 3;
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
sinon.restore(stripe.subscriptions.update);
|
||||
});
|
||||
await api.addSubToGroupUser(user, group);
|
||||
|
||||
it('updates a group plan quantity', async () => {
|
||||
data.paymentMethod = 'Stripe';
|
||||
await api.createSubscription(data);
|
||||
let updatedUser = await User.findById(user._id).exec();
|
||||
|
||||
let updatedGroup = await Group.findById(group._id).exec();
|
||||
expect(updatedGroup.purchased.plan.quantity).to.eql(3);
|
||||
|
||||
updatedGroup.memberCount += 1;
|
||||
await updatedGroup.save();
|
||||
|
||||
await api.updateStripeGroupPlan(updatedGroup, stripe);
|
||||
|
||||
expect(spy.calledOnce).to.be.true;
|
||||
expect(updatedGroup.purchased.plan.quantity).to.eql(4);
|
||||
});
|
||||
|
||||
it('does not update a group plan quantity that has a payment method other than stripe', async () => {
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedGroup = await Group.findById(group._id).exec();
|
||||
expect(updatedGroup.purchased.plan.quantity).to.eql(3);
|
||||
|
||||
updatedGroup.memberCount += 1;
|
||||
await updatedGroup.save();
|
||||
|
||||
await api.updateStripeGroupPlan(updatedGroup, stripe);
|
||||
|
||||
expect(spy.calledOnce).to.be.false;
|
||||
expect(updatedGroup.purchased.plan.quantity).to.eql(3);
|
||||
expect(updatedUser.purchased.plan.planId).to.eql('group_plan_auto');
|
||||
expect(updatedUser.purchased.plan.customerId).to.eql('group-plan');
|
||||
expect(updatedUser.purchased.plan.dateUpdated).to.exist;
|
||||
expect(updatedUser.purchased.plan.gemsBought).to.eql(0);
|
||||
expect(updatedUser.purchased.plan.paymentMethod).to.eql('Group Plan');
|
||||
expect(updatedUser.purchased.plan.extraMonths).to.eql(0);
|
||||
expect(updatedUser.purchased.plan.dateTerminated).to.eql(null);
|
||||
expect(updatedUser.purchased.plan.lastBillingDate).to.not.exist;
|
||||
expect(updatedUser.purchased.plan.dateCreated).to.exist;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,326 @@
|
||||
import moment from 'moment';
|
||||
|
||||
import * as sender from '../../../../../../../website/server/libs/email';
|
||||
import * as api from '../../../../../../../website/server/libs/payments';
|
||||
import { model as User } from '../../../../../../../website/server/models/user';
|
||||
import { model as Group } from '../../../../../../../website/server/models/group';
|
||||
import {
|
||||
generateGroup,
|
||||
} from '../../../../../../helpers/api-unit.helper.js';
|
||||
import i18n from '../../../../../../../website/common/script/i18n';
|
||||
|
||||
describe('Canceling a subscription for group', () => {
|
||||
let plan, group, user, data;
|
||||
|
||||
beforeEach(async () => {
|
||||
user = new User();
|
||||
user.profile.name = 'sender';
|
||||
await user.save();
|
||||
|
||||
group = generateGroup({
|
||||
name: 'test group',
|
||||
type: 'guild',
|
||||
privacy: 'public',
|
||||
leader: user._id,
|
||||
});
|
||||
await group.save();
|
||||
|
||||
data = {
|
||||
user,
|
||||
sub: {
|
||||
key: 'basic_3mo',
|
||||
},
|
||||
customerId: 'customer-id',
|
||||
paymentMethod: 'Payment Method',
|
||||
headers: {
|
||||
'x-client': 'habitica-web',
|
||||
'user-agent': '',
|
||||
},
|
||||
};
|
||||
|
||||
plan = {
|
||||
planId: 'basic_3mo',
|
||||
customerId: 'customer-id',
|
||||
dateUpdated: new Date(),
|
||||
gemsBought: 0,
|
||||
paymentMethod: 'paymentMethod',
|
||||
extraMonths: 0,
|
||||
dateTerminated: null,
|
||||
lastBillingDate: new Date(),
|
||||
dateCreated: new Date(),
|
||||
mysteryItems: [],
|
||||
consecutive: {
|
||||
trinkets: 0,
|
||||
offset: 0,
|
||||
gemCapExtra: 0,
|
||||
},
|
||||
};
|
||||
|
||||
sandbox.stub(sender, 'sendTxn');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sender.sendTxn.restore();
|
||||
});
|
||||
|
||||
it('adds a month termination date by default', async () => {
|
||||
data.groupId = group._id;
|
||||
await api.cancelSubscription(data);
|
||||
|
||||
let now = new Date();
|
||||
let updatedGroup = await Group.findById(group._id).exec();
|
||||
let daysTillTermination = moment(updatedGroup.purchased.plan.dateTerminated).diff(now, 'days');
|
||||
|
||||
expect(daysTillTermination).to.be.within(29, 30); // 1 month +/- 1 days
|
||||
});
|
||||
|
||||
it('adds extraMonths to dateTerminated value', async () => {
|
||||
group.purchased.plan.extraMonths = 2;
|
||||
await group.save();
|
||||
data.groupId = group._id;
|
||||
|
||||
await api.cancelSubscription(data);
|
||||
|
||||
let now = new Date();
|
||||
let updatedGroup = await Group.findById(group._id).exec();
|
||||
let daysTillTermination = moment(updatedGroup.purchased.plan.dateTerminated).diff(now, 'days');
|
||||
|
||||
expect(daysTillTermination).to.be.within(89, 90); // 3 months +/- 1 days
|
||||
});
|
||||
|
||||
it('handles extra month fractions', async () => {
|
||||
group.purchased.plan.extraMonths = 0.3;
|
||||
await group.save();
|
||||
data.groupId = group._id;
|
||||
|
||||
await api.cancelSubscription(data);
|
||||
|
||||
let now = new Date();
|
||||
let updatedGroup = await Group.findById(group._id).exec();
|
||||
let daysTillTermination = moment(updatedGroup.purchased.plan.dateTerminated).diff(now, 'days');
|
||||
|
||||
expect(daysTillTermination).to.be.within(38, 39); // should be about 1 month + 1/3 month
|
||||
});
|
||||
|
||||
it('terminates at next billing date if it exists', async () => {
|
||||
data.nextBill = moment().add({ days: 15 });
|
||||
data.groupId = group._id;
|
||||
|
||||
await api.cancelSubscription(data);
|
||||
|
||||
let now = new Date();
|
||||
let updatedGroup = await Group.findById(group._id).exec();
|
||||
let daysTillTermination = moment(updatedGroup.purchased.plan.dateTerminated).diff(now, 'days');
|
||||
|
||||
expect(daysTillTermination).to.be.within(13, 15);
|
||||
});
|
||||
|
||||
it('resets plan.extraMonths', async () => {
|
||||
group.purchased.plan.extraMonths = 5;
|
||||
await group.save();
|
||||
data.groupId = group._id;
|
||||
|
||||
await api.cancelSubscription(data);
|
||||
|
||||
let updatedGroup = await Group.findById(group._id).exec();
|
||||
expect(updatedGroup.purchased.plan.extraMonths).to.eql(0);
|
||||
});
|
||||
|
||||
it('sends an email', async () => {
|
||||
data.groupId = group._id;
|
||||
await api.cancelSubscription(data);
|
||||
|
||||
expect(sender.sendTxn).to.be.calledOnce;
|
||||
expect(sender.sendTxn.firstCall.args[0]._id).to.equal(user._id);
|
||||
expect(sender.sendTxn.firstCall.args[1]).to.equal('group-cancel-subscription');
|
||||
expect(sender.sendTxn.firstCall.args[2]).to.eql([
|
||||
{name: 'GROUP_NAME', content: group.name},
|
||||
]);
|
||||
});
|
||||
|
||||
it('prevents non group leader from manging subscription', async () => {
|
||||
let groupMember = new User();
|
||||
data.user = groupMember;
|
||||
data.groupId = group._id;
|
||||
|
||||
await expect(api.cancelSubscription(data))
|
||||
.eventually.be.rejected.and.to.eql({
|
||||
httpCode: 401,
|
||||
message: i18n.t('onlyGroupLeaderCanManageSubscription'),
|
||||
name: 'NotAuthorized',
|
||||
});
|
||||
});
|
||||
|
||||
it('allows old group leader to cancel if they created the subscription', async () => {
|
||||
data.groupId = group._id;
|
||||
data.sub = {
|
||||
key: 'group_monthly',
|
||||
};
|
||||
data.paymentMethod = 'Payment Method';
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedGroup = await Group.findById(group._id).exec();
|
||||
let newLeader = new User();
|
||||
updatedGroup.leader = newLeader._id;
|
||||
await updatedGroup.save();
|
||||
|
||||
await api.cancelSubscription(data);
|
||||
|
||||
updatedGroup = await Group.findById(group._id).exec();
|
||||
|
||||
expect(updatedGroup.purchased.plan.dateTerminated).to.exist;
|
||||
});
|
||||
|
||||
it('cancels member subscriptions', async () => {
|
||||
data = {
|
||||
user,
|
||||
sub: {
|
||||
key: 'basic_3mo',
|
||||
},
|
||||
customerId: 'customer-id',
|
||||
paymentMethod: 'Payment Method',
|
||||
headers: {
|
||||
'x-client': 'habitica-web',
|
||||
'user-agent': '',
|
||||
},
|
||||
};
|
||||
user.guilds.push(group._id);
|
||||
await user.save();
|
||||
expect(group.purchased.plan.planId).to.not.exist;
|
||||
data.groupId = group._id;
|
||||
await api.createSubscription(data);
|
||||
|
||||
await api.cancelSubscription(data);
|
||||
|
||||
let now = new Date();
|
||||
now.setHours(0, 0, 0, 0);
|
||||
let updatedLeader = await User.findById(user._id).exec();
|
||||
let daysTillTermination = moment(updatedLeader.purchased.plan.dateTerminated).diff(now, 'days');
|
||||
expect(daysTillTermination).to.be.within(2, 3); // only a few days
|
||||
});
|
||||
|
||||
it('sends an email to members of group', async () => {
|
||||
let recipient = new User();
|
||||
recipient.profile.name = 'recipient';
|
||||
recipient.guilds.push(group._id);
|
||||
await recipient.save();
|
||||
|
||||
data.groupId = group._id;
|
||||
|
||||
await api.createSubscription(data);
|
||||
await api.cancelSubscription(data);
|
||||
|
||||
expect(sender.sendTxn).to.be.have.callCount(4);
|
||||
expect(sender.sendTxn.thirdCall.args[0]._id).to.equal(recipient._id);
|
||||
expect(sender.sendTxn.thirdCall.args[1]).to.equal('group-member-cancel');
|
||||
expect(sender.sendTxn.thirdCall.args[2]).to.eql([
|
||||
{name: 'LEADER', content: user.profile.name},
|
||||
{name: 'GROUP_NAME', content: group.name},
|
||||
]);
|
||||
});
|
||||
|
||||
it('does not cancel member subscriptions when member does not have a group plan sub (i.e. UNLIMITED_CUSTOMER_ID)', async () => {
|
||||
plan.key = 'basic_earned';
|
||||
plan.customerId = api.constants.UNLIMITED_CUSTOMER_ID;
|
||||
|
||||
let recipient = new User();
|
||||
recipient.profile.name = 'recipient';
|
||||
recipient.purchased.plan = plan;
|
||||
recipient.guilds.push(group._id);
|
||||
await recipient.save();
|
||||
|
||||
data.groupId = group._id;
|
||||
|
||||
await api.cancelSubscription(data);
|
||||
|
||||
let updatedLeader = await User.findById(user._id).exec();
|
||||
expect(updatedLeader.purchased.plan.dateTerminated).to.not.exist;
|
||||
});
|
||||
|
||||
it('does not cancel a user subscription if they are still in another active group plan', async () => {
|
||||
let recipient = new User();
|
||||
recipient.profile.name = 'recipient';
|
||||
plan.key = 'basic_earned';
|
||||
recipient.purchased.plan = plan;
|
||||
recipient.guilds.push(group._id);
|
||||
await recipient.save();
|
||||
|
||||
user.guilds.push(group._id);
|
||||
await user.save();
|
||||
data.groupId = group._id;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedUser = await User.findById(recipient._id).exec();
|
||||
let firstDateCreated = updatedUser.purchased.plan.dateCreated;
|
||||
let extraMonthsBeforeSecond = updatedUser.purchased.plan.extraMonths;
|
||||
|
||||
let group2 = generateGroup({
|
||||
name: 'test group2',
|
||||
type: 'guild',
|
||||
privacy: 'public',
|
||||
leader: user._id,
|
||||
});
|
||||
data.groupId = group2._id;
|
||||
await group2.save();
|
||||
recipient.guilds.push(group2._id);
|
||||
await recipient.save();
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
await api.cancelSubscription(data);
|
||||
|
||||
updatedUser = await User.findById(recipient._id).exec();
|
||||
|
||||
expect(updatedUser.purchased.plan.planId).to.eql('group_plan_auto');
|
||||
expect(updatedUser.purchased.plan.customerId).to.eql('group-plan');
|
||||
expect(updatedUser.purchased.plan.dateUpdated).to.exist;
|
||||
expect(updatedUser.purchased.plan.gemsBought).to.eql(0);
|
||||
expect(updatedUser.purchased.plan.paymentMethod).to.eql('Group Plan');
|
||||
expect(updatedUser.purchased.plan.extraMonths).to.eql(extraMonthsBeforeSecond);
|
||||
expect(updatedUser.purchased.plan.dateTerminated).to.eql(null);
|
||||
expect(updatedUser.purchased.plan.lastBillingDate).to.not.exist;
|
||||
expect(updatedUser.purchased.plan.dateCreated).to.eql(firstDateCreated);
|
||||
});
|
||||
|
||||
it('does cancel a leader subscription with two cancelled group plans', async () => {
|
||||
user.guilds.push(group._id);
|
||||
await user.save();
|
||||
data.groupId = group._id;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedUser = await User.findById(user._id).exec();
|
||||
let firstDateCreated = updatedUser.purchased.plan.dateCreated;
|
||||
let extraMonthsBeforeSecond = updatedUser.purchased.plan.extraMonths;
|
||||
|
||||
let group2 = generateGroup({
|
||||
name: 'test group2',
|
||||
type: 'guild',
|
||||
privacy: 'public',
|
||||
leader: user._id,
|
||||
});
|
||||
user.guilds.push(group2._id);
|
||||
await user.save();
|
||||
data.groupId = group2._id;
|
||||
await group2.save();
|
||||
|
||||
await api.createSubscription(data);
|
||||
await api.cancelSubscription(data);
|
||||
|
||||
data.groupId = group._id;
|
||||
await api.cancelSubscription(data);
|
||||
|
||||
updatedUser = await User.findById(user._id).exec();
|
||||
|
||||
expect(updatedUser.purchased.plan.planId).to.eql('group_plan_auto');
|
||||
expect(updatedUser.purchased.plan.customerId).to.eql('group-plan');
|
||||
expect(updatedUser.purchased.plan.dateUpdated).to.exist;
|
||||
expect(updatedUser.purchased.plan.gemsBought).to.eql(0);
|
||||
expect(updatedUser.purchased.plan.paymentMethod).to.eql('Group Plan');
|
||||
expect(updatedUser.purchased.plan.extraMonths).to.eql(extraMonthsBeforeSecond);
|
||||
expect(updatedUser.purchased.plan.dateTerminated).to.exist;
|
||||
expect(updatedUser.purchased.plan.lastBillingDate).to.not.exist;
|
||||
expect(updatedUser.purchased.plan.dateCreated).to.eql(firstDateCreated);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,634 @@
|
||||
import moment from 'moment';
|
||||
import stripeModule from 'stripe';
|
||||
|
||||
import * as sender from '../../../../../../../website/server/libs/email';
|
||||
import * as api from '../../../../../../../website/server/libs/payments';
|
||||
import amzLib from '../../../../../../../website/server/libs/amazonPayments';
|
||||
import stripePayments from '../../../../../../../website/server/libs/stripePayments';
|
||||
import paypalPayments from '../../../../../../../website/server/libs/paypalPayments';
|
||||
import { model as User } from '../../../../../../../website/server/models/user';
|
||||
import { model as Group } from '../../../../../../../website/server/models/group';
|
||||
import {
|
||||
generateGroup,
|
||||
} from '../../../../../../helpers/api-unit.helper.js';
|
||||
|
||||
describe('Purchasing a subscription for group', () => {
|
||||
let plan, group, user, data;
|
||||
let stripe = stripeModule('test');
|
||||
|
||||
beforeEach(async () => {
|
||||
user = new User();
|
||||
user.profile.name = 'sender';
|
||||
await user.save();
|
||||
|
||||
group = generateGroup({
|
||||
name: 'test group',
|
||||
type: 'guild',
|
||||
privacy: 'public',
|
||||
leader: user._id,
|
||||
});
|
||||
await group.save();
|
||||
|
||||
data = {
|
||||
user,
|
||||
sub: {
|
||||
key: 'basic_3mo',
|
||||
},
|
||||
customerId: 'customer-id',
|
||||
paymentMethod: 'Payment Method',
|
||||
headers: {
|
||||
'x-client': 'habitica-web',
|
||||
'user-agent': '',
|
||||
},
|
||||
};
|
||||
|
||||
plan = {
|
||||
planId: 'basic_3mo',
|
||||
customerId: 'customer-id',
|
||||
dateUpdated: new Date(),
|
||||
gemsBought: 0,
|
||||
paymentMethod: 'paymentMethod',
|
||||
extraMonths: 0,
|
||||
dateTerminated: null,
|
||||
lastBillingDate: new Date(),
|
||||
dateCreated: new Date(),
|
||||
mysteryItems: [],
|
||||
consecutive: {
|
||||
trinkets: 0,
|
||||
offset: 0,
|
||||
gemCapExtra: 0,
|
||||
},
|
||||
};
|
||||
|
||||
let subscriptionId = 'subId';
|
||||
sinon.stub(stripe.customers, 'del').returnsPromise().resolves({});
|
||||
|
||||
let currentPeriodEndTimeStamp = moment().add(3, 'months').unix();
|
||||
sinon.stub(stripe.customers, 'retrieve')
|
||||
.returnsPromise().resolves({
|
||||
subscriptions: {
|
||||
data: [{id: subscriptionId, current_period_end: currentPeriodEndTimeStamp}], // eslint-disable-line camelcase
|
||||
},
|
||||
});
|
||||
|
||||
stripePayments.setStripeApi(stripe);
|
||||
sandbox.stub(sender, 'sendTxn');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
stripe.customers.del.restore();
|
||||
stripe.customers.retrieve.restore();
|
||||
sender.sendTxn.restore();
|
||||
});
|
||||
|
||||
it('creates a subscription', async () => {
|
||||
expect(group.purchased.plan.planId).to.not.exist;
|
||||
data.groupId = group._id;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedGroup = await Group.findById(group._id).exec();
|
||||
|
||||
expect(updatedGroup.purchased.plan.planId).to.eql('basic_3mo');
|
||||
expect(updatedGroup.purchased.plan.customerId).to.eql('customer-id');
|
||||
expect(updatedGroup.purchased.plan.dateUpdated).to.exist;
|
||||
expect(updatedGroup.purchased.plan.gemsBought).to.eql(0);
|
||||
expect(updatedGroup.purchased.plan.paymentMethod).to.eql('Payment Method');
|
||||
expect(updatedGroup.purchased.plan.extraMonths).to.eql(0);
|
||||
expect(updatedGroup.purchased.plan.dateTerminated).to.eql(null);
|
||||
expect(updatedGroup.purchased.plan.lastBillingDate).to.not.exist;
|
||||
expect(updatedGroup.purchased.plan.dateCreated).to.exist;
|
||||
});
|
||||
|
||||
it('sends an email', async () => {
|
||||
expect(group.purchased.plan.planId).to.not.exist;
|
||||
data.groupId = group._id;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(sender.sendTxn).to.be.calledWith(user, 'group-subscription-begins');
|
||||
});
|
||||
|
||||
it('sets extraMonths if plan has dateTerminated date', async () => {
|
||||
group.purchased.plan = plan;
|
||||
group.purchased.plan.dateTerminated = moment(new Date()).add(2, 'months');
|
||||
await group.save();
|
||||
expect(group.purchased.plan.extraMonths).to.eql(0);
|
||||
data.groupId = group._id;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedGroup = await Group.findById(group._id).exec();
|
||||
expect(updatedGroup.purchased.plan.extraMonths).to.within(1.9, 2);
|
||||
});
|
||||
|
||||
it('does not set negative extraMonths if plan has past dateTerminated date', async () => {
|
||||
group.purchased.plan = plan;
|
||||
group.purchased.plan.dateTerminated = moment(new Date()).subtract(2, 'months');
|
||||
await group.save();
|
||||
expect(group.purchased.plan.extraMonths).to.eql(0);
|
||||
data.groupId = group._id;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedGroup = await Group.findById(group._id).exec();
|
||||
expect(updatedGroup.purchased.plan.extraMonths).to.eql(0);
|
||||
});
|
||||
|
||||
it('grants all members of a group a subscription', async () => {
|
||||
user.guilds.push(group._id);
|
||||
await user.save();
|
||||
expect(group.purchased.plan.planId).to.not.exist;
|
||||
data.groupId = group._id;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedLeader = await User.findById(user._id).exec();
|
||||
|
||||
expect(updatedLeader.purchased.plan.planId).to.eql('group_plan_auto');
|
||||
expect(updatedLeader.purchased.plan.customerId).to.eql('group-plan');
|
||||
expect(updatedLeader.purchased.plan.dateUpdated).to.exist;
|
||||
expect(updatedLeader.purchased.plan.gemsBought).to.eql(0);
|
||||
expect(updatedLeader.purchased.plan.paymentMethod).to.eql('Group Plan');
|
||||
expect(updatedLeader.purchased.plan.extraMonths).to.eql(0);
|
||||
expect(updatedLeader.purchased.plan.dateTerminated).to.eql(null);
|
||||
expect(updatedLeader.purchased.plan.lastBillingDate).to.not.exist;
|
||||
expect(updatedLeader.purchased.plan.dateCreated).to.exist;
|
||||
});
|
||||
|
||||
it('sends an email to members of group', async () => {
|
||||
let recipient = new User();
|
||||
recipient.profile.name = 'recipient';
|
||||
recipient.guilds.push(group._id);
|
||||
await recipient.save();
|
||||
|
||||
data.groupId = group._id;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(sender.sendTxn).to.be.calledTwice;
|
||||
expect(sender.sendTxn.firstCall.args[0]._id).to.equal(recipient._id);
|
||||
expect(sender.sendTxn.firstCall.args[1]).to.equal('group-member-joining');
|
||||
expect(sender.sendTxn.firstCall.args[2]).to.eql([
|
||||
{name: 'LEADER', content: user.profile.name},
|
||||
{name: 'GROUP_NAME', content: group.name},
|
||||
]);
|
||||
});
|
||||
|
||||
it('adds months to members with existing gift subscription', async () => {
|
||||
let recipient = new User();
|
||||
recipient.profile.name = 'recipient';
|
||||
recipient.purchased.plan = plan;
|
||||
recipient.guilds.push(group._id);
|
||||
plan.planId = 'basic_earned';
|
||||
plan.paymentMethod = 'paymentMethod';
|
||||
data.gift = {
|
||||
member: recipient,
|
||||
subscription: {
|
||||
key: 'basic_earned',
|
||||
months: 1,
|
||||
},
|
||||
};
|
||||
await api.createSubscription(data);
|
||||
await recipient.save();
|
||||
|
||||
data.gift = undefined;
|
||||
|
||||
user.guilds.push(group._id);
|
||||
await user.save();
|
||||
data.groupId = group._id;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedUser = await User.findById(recipient._id).exec();
|
||||
|
||||
expect(updatedUser.purchased.plan.planId).to.eql('group_plan_auto');
|
||||
expect(updatedUser.purchased.plan.customerId).to.eql('group-plan');
|
||||
expect(updatedUser.purchased.plan.dateUpdated).to.exist;
|
||||
expect(updatedUser.purchased.plan.gemsBought).to.eql(0);
|
||||
expect(updatedUser.purchased.plan.paymentMethod).to.eql('Group Plan');
|
||||
expect(updatedUser.purchased.plan.extraMonths).to.within(1, 3);
|
||||
expect(updatedUser.purchased.plan.dateTerminated).to.eql(null);
|
||||
expect(updatedUser.purchased.plan.lastBillingDate).to.not.exist;
|
||||
expect(updatedUser.purchased.plan.dateCreated).to.exist;
|
||||
});
|
||||
|
||||
it('adds months to members with existing multi-month gift subscription', async () => {
|
||||
let recipient = new User();
|
||||
recipient.profile.name = 'recipient';
|
||||
recipient.purchased.plan = plan;
|
||||
recipient.guilds.push(group._id);
|
||||
data.gift = {
|
||||
member: recipient,
|
||||
subscription: {
|
||||
key: 'basic_3mo',
|
||||
months: 3,
|
||||
},
|
||||
};
|
||||
await api.createSubscription(data);
|
||||
await recipient.save();
|
||||
|
||||
data.gift = undefined;
|
||||
|
||||
user.guilds.push(group._id);
|
||||
await user.save();
|
||||
data.groupId = group._id;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedUser = await User.findById(recipient._id).exec();
|
||||
|
||||
expect(updatedUser.purchased.plan.planId).to.eql('group_plan_auto');
|
||||
expect(updatedUser.purchased.plan.customerId).to.eql('group-plan');
|
||||
expect(updatedUser.purchased.plan.dateUpdated).to.exist;
|
||||
expect(updatedUser.purchased.plan.gemsBought).to.eql(0);
|
||||
expect(updatedUser.purchased.plan.paymentMethod).to.eql('Group Plan');
|
||||
expect(updatedUser.purchased.plan.extraMonths).to.within(3, 5);
|
||||
expect(updatedUser.purchased.plan.dateTerminated).to.eql(null);
|
||||
expect(updatedUser.purchased.plan.lastBillingDate).to.not.exist;
|
||||
expect(updatedUser.purchased.plan.dateCreated).to.exist;
|
||||
});
|
||||
|
||||
it('adds months to members with existing recurring subscription (Stripe)', async () => {
|
||||
let recipient = new User();
|
||||
recipient.profile.name = 'recipient';
|
||||
plan.key = 'basic_earned';
|
||||
plan.paymentMethod = stripePayments.constants.PAYMENT_METHOD;
|
||||
recipient.purchased.plan = plan;
|
||||
recipient.guilds.push(group._id);
|
||||
await recipient.save();
|
||||
|
||||
user.guilds.push(group._id);
|
||||
await user.save();
|
||||
data.groupId = group._id;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedUser = await User.findById(recipient._id).exec();
|
||||
|
||||
expect(updatedUser.purchased.plan.extraMonths).to.within(2, 3);
|
||||
});
|
||||
|
||||
it('adds months to members with existing recurring subscription (Amazon)', async () => {
|
||||
sinon.stub(amzLib, 'getBillingAgreementDetails')
|
||||
.returnsPromise()
|
||||
.resolves({
|
||||
BillingAgreementDetails: {
|
||||
BillingAgreementStatus: {State: 'Closed'},
|
||||
},
|
||||
});
|
||||
|
||||
let recipient = new User();
|
||||
recipient.profile.name = 'recipient';
|
||||
plan.planId = 'basic_earned';
|
||||
plan.paymentMethod = amzLib.constants.PAYMENT_METHOD;
|
||||
plan.lastBillingDate = moment().add(3, 'months');
|
||||
recipient.purchased.plan = plan;
|
||||
recipient.guilds.push(group._id);
|
||||
|
||||
await recipient.save();
|
||||
|
||||
user.guilds.push(group._id);
|
||||
await user.save();
|
||||
data.groupId = group._id;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedUser = await User.findById(recipient._id).exec();
|
||||
|
||||
expect(updatedUser.purchased.plan.extraMonths).to.within(3, 4);
|
||||
});
|
||||
|
||||
it('adds months to members with existing recurring subscription (Paypal)', async () => {
|
||||
sinon.stub(paypalPayments, 'paypalBillingAgreementCancel').returnsPromise().resolves({});
|
||||
sinon.stub(paypalPayments, 'paypalBillingAgreementGet')
|
||||
.returnsPromise().resolves({
|
||||
agreement_details: { // eslint-disable-line camelcase
|
||||
next_billing_date: moment().add(3, 'months').toDate(), // eslint-disable-line camelcase
|
||||
cycles_completed: 1, // eslint-disable-line camelcase
|
||||
},
|
||||
});
|
||||
|
||||
let recipient = new User();
|
||||
recipient.profile.name = 'recipient';
|
||||
plan.planId = 'basic_earned';
|
||||
plan.paymentMethod = paypalPayments.constants.PAYMENT_METHOD;
|
||||
recipient.purchased.plan = plan;
|
||||
recipient.guilds.push(group._id);
|
||||
|
||||
await recipient.save();
|
||||
|
||||
user.guilds.push(group._id);
|
||||
await user.save();
|
||||
data.groupId = group._id;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedUser = await User.findById(recipient._id).exec();
|
||||
|
||||
expect(updatedUser.purchased.plan.extraMonths).to.within(2, 3);
|
||||
paypalPayments.paypalBillingAgreementGet.restore();
|
||||
paypalPayments.paypalBillingAgreementCancel.restore();
|
||||
});
|
||||
|
||||
it('adds months to members with existing recurring subscription (Android)');
|
||||
it('adds months to members with existing recurring subscription (iOs)');
|
||||
|
||||
it('adds months to members who already cancelled but not yet terminated recurring subscription', async () => {
|
||||
let recipient = new User();
|
||||
recipient.profile.name = 'recipient';
|
||||
plan.key = 'basic_earned';
|
||||
plan.paymentMethod = stripePayments.constants.PAYMENT_METHOD;
|
||||
recipient.purchased.plan = plan;
|
||||
recipient.guilds.push(group._id);
|
||||
await recipient.save();
|
||||
|
||||
user.guilds.push(group._id);
|
||||
await user.save();
|
||||
data.groupId = group._id;
|
||||
|
||||
await recipient.cancelSubscription();
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedUser = await User.findById(recipient._id).exec();
|
||||
|
||||
expect(updatedUser.purchased.plan.extraMonths).to.within(2, 3);
|
||||
});
|
||||
|
||||
it('adds months to members who already cancelled but not yet terminated group plan subscription', async () => {
|
||||
let recipient = new User();
|
||||
recipient.profile.name = 'recipient';
|
||||
plan.key = 'basic_earned';
|
||||
plan.paymentMethod = api.constants.GROUP_PLAN_PAYMENT_METHOD;
|
||||
plan.extraMonths = 2.94;
|
||||
recipient.purchased.plan = plan;
|
||||
recipient.guilds.push(group._id);
|
||||
await recipient.save();
|
||||
|
||||
user.guilds.push(group._id);
|
||||
await user.save();
|
||||
data.groupId = group._id;
|
||||
|
||||
await recipient.cancelSubscription();
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedUser = await User.findById(recipient._id).exec();
|
||||
expect(updatedUser.purchased.plan.extraMonths).to.within(3, 4);
|
||||
});
|
||||
|
||||
it('resets date terminated if user has old subscription', async () => {
|
||||
let recipient = new User();
|
||||
recipient.profile.name = 'recipient';
|
||||
plan.key = 'basic_earned';
|
||||
plan.paymentMethod = stripePayments.constants.PAYMENT_METHOD;
|
||||
plan.dateTerminated = moment().subtract(1, 'days').toDate();
|
||||
recipient.purchased.plan = plan;
|
||||
recipient.guilds.push(group._id);
|
||||
await recipient.save();
|
||||
|
||||
user.guilds.push(group._id);
|
||||
await user.save();
|
||||
data.groupId = group._id;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedUser = await User.findById(recipient._id).exec();
|
||||
|
||||
expect(updatedUser.purchased.plan.dateTerminated).to.not.exist;
|
||||
});
|
||||
|
||||
it('adds months to members with existing recurring subscription and includes existing extraMonths', async () => {
|
||||
let recipient = new User();
|
||||
recipient.profile.name = 'recipient';
|
||||
plan.key = 'basic_earned';
|
||||
plan.paymentMethod = stripePayments.constants.PAYMENT_METHOD;
|
||||
plan.extraMonths = 5;
|
||||
recipient.purchased.plan = plan;
|
||||
recipient.guilds.push(group._id);
|
||||
await recipient.save();
|
||||
|
||||
user.guilds.push(group._id);
|
||||
await user.save();
|
||||
data.groupId = group._id;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedUser = await User.findById(recipient._id).exec();
|
||||
|
||||
expect(updatedUser.purchased.plan.extraMonths).to.within(7, 8);
|
||||
});
|
||||
|
||||
it('adds months to members with existing recurring subscription and ignores existing negative extraMonths', async () => {
|
||||
let recipient = new User();
|
||||
recipient.profile.name = 'recipient';
|
||||
plan.key = 'basic_earned';
|
||||
plan.paymentMethod = stripePayments.constants.PAYMENT_METHOD;
|
||||
plan.extraMonths = -5;
|
||||
recipient.purchased.plan = plan;
|
||||
recipient.guilds.push(group._id);
|
||||
await recipient.save();
|
||||
|
||||
user.guilds.push(group._id);
|
||||
await user.save();
|
||||
data.groupId = group._id;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedUser = await User.findById(recipient._id).exec();
|
||||
|
||||
expect(updatedUser.purchased.plan.extraMonths).to.within(2, 3);
|
||||
});
|
||||
|
||||
it('does not override gemsBought, mysteryItems, dateCreated, and consective fields', async () => {
|
||||
let planCreatedDate = moment().toDate();
|
||||
let mysteryItem = {title: 'item'};
|
||||
let mysteryItems = [mysteryItem];
|
||||
let consecutive = {
|
||||
trinkets: 3,
|
||||
gemCapExtra: 20,
|
||||
offset: 1,
|
||||
count: 13,
|
||||
};
|
||||
|
||||
let recipient = new User();
|
||||
recipient.profile.name = 'recipient';
|
||||
|
||||
plan.key = 'basic_earned';
|
||||
plan.gemsBought = 3;
|
||||
plan.dateCreated = planCreatedDate;
|
||||
plan.mysteryItems = mysteryItems;
|
||||
plan.consecutive = consecutive;
|
||||
|
||||
recipient.purchased.plan = plan;
|
||||
recipient.guilds.push(group._id);
|
||||
await recipient.save();
|
||||
|
||||
user.guilds.push(group._id);
|
||||
await user.save();
|
||||
data.groupId = group._id;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedUser = await User.findById(recipient._id).exec();
|
||||
|
||||
expect(updatedUser.purchased.plan.gemsBought).to.equal(3);
|
||||
expect(updatedUser.purchased.plan.mysteryItems[0]).to.eql(mysteryItem);
|
||||
expect(updatedUser.purchased.plan.consecutive.count).to.equal(consecutive.count);
|
||||
expect(updatedUser.purchased.plan.consecutive.offset).to.equal(consecutive.offset);
|
||||
expect(updatedUser.purchased.plan.consecutive.gemCapExtra).to.equal(consecutive.gemCapExtra);
|
||||
expect(updatedUser.purchased.plan.consecutive.trinkets).to.equal(consecutive.trinkets);
|
||||
expect(updatedUser.purchased.plan.dateCreated).to.eql(planCreatedDate);
|
||||
});
|
||||
|
||||
it('does not modify a user with a group subscription when they join another group', async () => {
|
||||
let recipient = new User();
|
||||
recipient.profile.name = 'recipient';
|
||||
plan.key = 'basic_earned';
|
||||
recipient.purchased.plan = plan;
|
||||
recipient.guilds.push(group._id);
|
||||
await recipient.save();
|
||||
|
||||
user.guilds.push(group._id);
|
||||
await user.save();
|
||||
data.groupId = group._id;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedUser = await User.findById(recipient._id).exec();
|
||||
let firstDateCreated = updatedUser.purchased.plan.dateCreated;
|
||||
let extraMonthsBeforeSecond = updatedUser.purchased.plan.extraMonths;
|
||||
|
||||
let group2 = generateGroup({
|
||||
name: 'test group2',
|
||||
type: 'guild',
|
||||
privacy: 'public',
|
||||
leader: user._id,
|
||||
});
|
||||
data.groupId = group2._id;
|
||||
await group2.save();
|
||||
recipient.guilds.push(group2._id);
|
||||
await recipient.save();
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
updatedUser = await User.findById(recipient._id).exec();
|
||||
|
||||
expect(updatedUser.purchased.plan.planId).to.eql('group_plan_auto');
|
||||
expect(updatedUser.purchased.plan.customerId).to.eql('group-plan');
|
||||
expect(updatedUser.purchased.plan.dateUpdated).to.exist;
|
||||
expect(updatedUser.purchased.plan.gemsBought).to.eql(0);
|
||||
expect(updatedUser.purchased.plan.paymentMethod).to.eql('Group Plan');
|
||||
expect(updatedUser.purchased.plan.extraMonths).to.eql(extraMonthsBeforeSecond);
|
||||
expect(updatedUser.purchased.plan.dateTerminated).to.eql(null);
|
||||
expect(updatedUser.purchased.plan.lastBillingDate).to.not.exist;
|
||||
expect(updatedUser.purchased.plan.dateCreated).to.eql(firstDateCreated);
|
||||
});
|
||||
|
||||
it('does not remove a user who is in two groups plans and leaves one', async () => {
|
||||
let recipient = new User();
|
||||
recipient.profile.name = 'recipient';
|
||||
plan.key = 'basic_earned';
|
||||
recipient.purchased.plan = plan;
|
||||
recipient.guilds.push(group._id);
|
||||
await recipient.save();
|
||||
|
||||
user.guilds.push(group._id);
|
||||
await user.save();
|
||||
data.groupId = group._id;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedUser = await User.findById(recipient._id).exec();
|
||||
let firstDateCreated = updatedUser.purchased.plan.dateCreated;
|
||||
let extraMonthsBeforeSecond = updatedUser.purchased.plan.extraMonths;
|
||||
|
||||
let group2 = generateGroup({
|
||||
name: 'test group2',
|
||||
type: 'guild',
|
||||
privacy: 'public',
|
||||
leader: user._id,
|
||||
});
|
||||
data.groupId = group2._id;
|
||||
await group2.save();
|
||||
recipient.guilds.push(group2._id);
|
||||
await recipient.save();
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedGroup = await Group.findById(group._id).exec();
|
||||
await updatedGroup.leave(recipient);
|
||||
|
||||
updatedUser = await User.findById(recipient._id).exec();
|
||||
|
||||
expect(updatedUser.purchased.plan.planId).to.eql('group_plan_auto');
|
||||
expect(updatedUser.purchased.plan.customerId).to.eql('group-plan');
|
||||
expect(updatedUser.purchased.plan.dateUpdated).to.exist;
|
||||
expect(updatedUser.purchased.plan.gemsBought).to.eql(0);
|
||||
expect(updatedUser.purchased.plan.paymentMethod).to.eql('Group Plan');
|
||||
expect(updatedUser.purchased.plan.extraMonths).to.eql(extraMonthsBeforeSecond);
|
||||
expect(updatedUser.purchased.plan.dateTerminated).to.eql(null);
|
||||
expect(updatedUser.purchased.plan.lastBillingDate).to.not.exist;
|
||||
expect(updatedUser.purchased.plan.dateCreated).to.eql(firstDateCreated);
|
||||
});
|
||||
|
||||
it('does not modify a user with an unlimited subscription', async () => {
|
||||
plan.key = 'basic_earned';
|
||||
plan.customerId = api.constants.UNLIMITED_CUSTOMER_ID;
|
||||
|
||||
let recipient = new User();
|
||||
recipient.profile.name = 'recipient';
|
||||
recipient.purchased.plan = plan;
|
||||
recipient.guilds.push(group._id);
|
||||
await recipient.save();
|
||||
|
||||
user.guilds.push(group._id);
|
||||
await user.save();
|
||||
data.groupId = group._id;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedUser = await User.findById(recipient._id).exec();
|
||||
|
||||
expect(updatedUser.purchased.plan.planId).to.eql('basic_3mo');
|
||||
expect(updatedUser.purchased.plan.customerId).to.eql(api.constants.UNLIMITED_CUSTOMER_ID);
|
||||
expect(updatedUser.purchased.plan.dateUpdated).to.exist;
|
||||
expect(updatedUser.purchased.plan.gemsBought).to.eql(0);
|
||||
expect(updatedUser.purchased.plan.paymentMethod).to.eql('paymentMethod');
|
||||
expect(updatedUser.purchased.plan.extraMonths).to.eql(0);
|
||||
expect(updatedUser.purchased.plan.dateTerminated).to.eql(null);
|
||||
expect(updatedUser.purchased.plan.lastBillingDate).to.exist;
|
||||
expect(updatedUser.purchased.plan.dateCreated).to.exist;
|
||||
});
|
||||
|
||||
it('updates a user with a cancelled but active group subscription', async () => {
|
||||
plan.key = 'basic_earned';
|
||||
plan.customerId = api.constants.GROUP_PLAN_CUSTOMER_ID;
|
||||
plan.dateTerminated = moment().add(1, 'months');
|
||||
|
||||
let recipient = new User();
|
||||
recipient.profile.name = 'recipient';
|
||||
recipient.purchased.plan = plan;
|
||||
recipient.guilds.push(group._id);
|
||||
await recipient.save();
|
||||
|
||||
user.guilds.push(group._id);
|
||||
await user.save();
|
||||
data.groupId = group._id;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
let updatedUser = await User.findById(recipient._id).exec();
|
||||
|
||||
expect(updatedUser.purchased.plan.planId).to.eql('group_plan_auto');
|
||||
expect(updatedUser.purchased.plan.customerId).to.eql(api.constants.GROUP_PLAN_CUSTOMER_ID);
|
||||
expect(updatedUser.purchased.plan.dateUpdated).to.exist;
|
||||
expect(updatedUser.purchased.plan.gemsBought).to.eql(0);
|
||||
expect(updatedUser.purchased.plan.paymentMethod).to.eql('Group Plan');
|
||||
expect(updatedUser.purchased.plan.extraMonths).to.within(0, 2);
|
||||
expect(updatedUser.purchased.plan.dateTerminated).to.eql(null);
|
||||
expect(updatedUser.purchased.plan.lastBillingDate).to.not.exist;
|
||||
expect(updatedUser.purchased.plan.dateCreated).to.exist;
|
||||
});
|
||||
});
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
generateGroup,
|
||||
} from '../../../../helpers/api-unit.helper.js';
|
||||
import { model as User } from '../../../../../website/server/models/user';
|
||||
import { model as Group } from '../../../../../website/server/models/group';
|
||||
import { model as Coupon } from '../../../../../website/server/models/coupon';
|
||||
import stripePayments from '../../../../../website/server/libs/stripePayments';
|
||||
import payments from '../../../../../website/server/libs/payments';
|
||||
@@ -658,4 +659,60 @@ describe('Stripe Payments', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#upgradeGroupPlan', () => {
|
||||
let spy, data, user, group;
|
||||
|
||||
beforeEach(async function () {
|
||||
user = new User();
|
||||
user.profile.name = 'sender';
|
||||
|
||||
data = {
|
||||
user,
|
||||
sub: {
|
||||
key: 'basic_3mo', // @TODO: Validate that this is group
|
||||
},
|
||||
customerId: 'customer-id',
|
||||
paymentMethod: 'Payment Method',
|
||||
headers: {
|
||||
'x-client': 'habitica-web',
|
||||
'user-agent': '',
|
||||
},
|
||||
};
|
||||
|
||||
group = generateGroup({
|
||||
name: 'test group',
|
||||
type: 'guild',
|
||||
privacy: 'public',
|
||||
leader: user._id,
|
||||
});
|
||||
await group.save();
|
||||
|
||||
spy = sinon.stub(stripe.subscriptions, 'update');
|
||||
spy.returnsPromise().resolves([]);
|
||||
data.groupId = group._id;
|
||||
data.sub.quantity = 3;
|
||||
stripePayments.setStripeApi(stripe);
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
sinon.restore(stripe.subscriptions.update);
|
||||
});
|
||||
|
||||
it('updates a group plan quantity', async () => {
|
||||
data.paymentMethod = 'Stripe';
|
||||
await payments.createSubscription(data);
|
||||
|
||||
let updatedGroup = await Group.findById(group._id).exec();
|
||||
expect(updatedGroup.purchased.plan.quantity).to.eql(3);
|
||||
|
||||
updatedGroup.memberCount += 1;
|
||||
await updatedGroup.save();
|
||||
|
||||
await stripePayments.chargeForAdditionalGroupMember(updatedGroup);
|
||||
|
||||
expect(spy.calledOnce).to.be.true;
|
||||
expect(updatedGroup.purchased.plan.quantity).to.eql(4);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
import moment from 'moment';
|
||||
import { v4 as generateUUID } from 'uuid';
|
||||
import validator from 'validator';
|
||||
import { sleep } from '../../../../helpers/api-unit.helper';
|
||||
import { model as Group, INVITES_LIMIT } from '../../../../../website/server/models/group';
|
||||
import { model as User } from '../../../../../website/server/models/user';
|
||||
@@ -7,9 +10,7 @@ import {
|
||||
import { quests as questScrolls } from '../../../../../website/common/script/content';
|
||||
import { groupChatReceivedWebhook } from '../../../../../website/server/libs/webhook';
|
||||
import * as email from '../../../../../website/server/libs/email';
|
||||
import validator from 'validator';
|
||||
import { TAVERN_ID } from '../../../../../website/common/script/';
|
||||
import { v4 as generateUUID } from 'uuid';
|
||||
import shared from '../../../../../website/common';
|
||||
|
||||
describe('Group Model', () => {
|
||||
@@ -667,6 +668,49 @@ describe('Group Model', () => {
|
||||
expect(party.memberCount).to.eql(1);
|
||||
});
|
||||
|
||||
it('does not allow a leader to leave a group with an active subscription', async () => {
|
||||
party.memberCount = 2;
|
||||
party.purchased.plan.customerId = '110002222333';
|
||||
|
||||
await expect(party.leave(questLeader))
|
||||
.to.eventually.be.rejected.and.to.eql({
|
||||
name: 'NotAuthorized',
|
||||
httpCode: 401,
|
||||
message: shared.i18n.t('leaderCannotLeaveGroupWithActiveGroup'),
|
||||
});
|
||||
|
||||
party = await Group.findOne({_id: party._id});
|
||||
expect(party).to.exist;
|
||||
expect(party.memberCount).to.eql(1);
|
||||
});
|
||||
|
||||
it('deletes a private group when the last member leaves and a subscription is cancelled', async () => {
|
||||
let guild = new Group({
|
||||
name: 'test guild',
|
||||
type: 'guild',
|
||||
memberCount: 1,
|
||||
});
|
||||
|
||||
let leader = new User({
|
||||
guilds: [guild._id],
|
||||
});
|
||||
|
||||
guild.leader = leader._id;
|
||||
|
||||
await Promise.all([
|
||||
guild.save(),
|
||||
leader.save(),
|
||||
]);
|
||||
|
||||
guild.purchased.plan.customerId = '110002222333';
|
||||
guild.purchased.plan.dateTerminated = new Date();
|
||||
|
||||
await guild.leave(leader);
|
||||
|
||||
party = await Group.findOne({_id: guild._id});
|
||||
expect(party).to.not.exist;
|
||||
});
|
||||
|
||||
it('does not delete a public group when the last member leaves', async () => {
|
||||
party.privacy = 'public';
|
||||
|
||||
@@ -1545,5 +1589,57 @@ describe('Group Model', () => {
|
||||
expect(args.find(arg => arg[0][0].id === memberWithWebhook3.webhooks[0].id)).to.be.exist;
|
||||
});
|
||||
});
|
||||
|
||||
context('isSubscribed', () => {
|
||||
it('returns false if group does not have customer id', () => {
|
||||
expect(party.isSubscribed()).to.be.undefined;
|
||||
});
|
||||
|
||||
it('returns true if group does not have plan.dateTerminated', () => {
|
||||
party.purchased.plan.customerId = 'test-id';
|
||||
|
||||
expect(party.isSubscribed()).to.be.true;
|
||||
});
|
||||
|
||||
it('returns true if group if plan.dateTerminated is after today', () => {
|
||||
party.purchased.plan.customerId = 'test-id';
|
||||
party.purchased.plan.dateTerminated = moment().add(1, 'days').toDate();
|
||||
|
||||
expect(party.isSubscribed()).to.be.true;
|
||||
});
|
||||
|
||||
it('returns false if group if plan.dateTerminated is before today', () => {
|
||||
party.purchased.plan.customerId = 'test-id';
|
||||
party.purchased.plan.dateTerminated = moment().subtract(1, 'days').toDate();
|
||||
|
||||
expect(party.isSubscribed()).to.be.false;
|
||||
});
|
||||
});
|
||||
|
||||
context('hasNotCancelled', () => {
|
||||
it('returns false if group does not have customer id', () => {
|
||||
expect(party.hasNotCancelled()).to.be.undefined;
|
||||
});
|
||||
|
||||
it('returns true if party does not have plan.dateTerminated', () => {
|
||||
party.purchased.plan.customerId = 'test-id';
|
||||
|
||||
expect(party.hasNotCancelled()).to.be.true;
|
||||
});
|
||||
|
||||
it('returns false if party if plan.dateTerminated is after today', () => {
|
||||
party.purchased.plan.customerId = 'test-id';
|
||||
party.purchased.plan.dateTerminated = moment().add(1, 'days').toDate();
|
||||
|
||||
expect(party.hasNotCancelled()).to.be.false;
|
||||
});
|
||||
|
||||
it('returns false if party if plan.dateTerminated is before today', () => {
|
||||
party.purchased.plan.customerId = 'test-id';
|
||||
party.purchased.plan.dateTerminated = moment().subtract(1, 'days').toDate();
|
||||
|
||||
expect(party.hasNotCancelled()).to.be.false;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import Bluebird from 'bluebird';
|
||||
import moment from 'moment';
|
||||
import { model as User } from '../../../../../website/server/models/user';
|
||||
import common from '../../../../../website/common';
|
||||
import Bluebird from 'bluebird';
|
||||
|
||||
describe('User Model', () => {
|
||||
it('keeps user._tmp when calling .toJSON', () => {
|
||||
@@ -145,4 +146,68 @@ describe('User Model', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('isSubscribed', () => {
|
||||
let user;
|
||||
beforeEach(() => {
|
||||
user = new User();
|
||||
});
|
||||
|
||||
|
||||
it('returns false if user does not have customer id', () => {
|
||||
expect(user.isSubscribed()).to.be.undefined;
|
||||
});
|
||||
|
||||
it('returns true if user does not have plan.dateTerminated', () => {
|
||||
user.purchased.plan.customerId = 'test-id';
|
||||
|
||||
expect(user.isSubscribed()).to.be.true;
|
||||
});
|
||||
|
||||
it('returns true if user if plan.dateTerminated is after today', () => {
|
||||
user.purchased.plan.customerId = 'test-id';
|
||||
user.purchased.plan.dateTerminated = moment().add(1, 'days').toDate();
|
||||
|
||||
expect(user.isSubscribed()).to.be.true;
|
||||
});
|
||||
|
||||
it('returns false if user if plan.dateTerminated is before today', () => {
|
||||
user.purchased.plan.customerId = 'test-id';
|
||||
user.purchased.plan.dateTerminated = moment().subtract(1, 'days').toDate();
|
||||
|
||||
expect(user.isSubscribed()).to.be.false;
|
||||
});
|
||||
});
|
||||
|
||||
context('hasNotCancelled', () => {
|
||||
let user;
|
||||
beforeEach(() => {
|
||||
user = new User();
|
||||
});
|
||||
|
||||
|
||||
it('returns false if user does not have customer id', () => {
|
||||
expect(user.hasNotCancelled()).to.be.undefined;
|
||||
});
|
||||
|
||||
it('returns true if user does not have plan.dateTerminated', () => {
|
||||
user.purchased.plan.customerId = 'test-id';
|
||||
|
||||
expect(user.hasNotCancelled()).to.be.true;
|
||||
});
|
||||
|
||||
it('returns false if user if plan.dateTerminated is after today', () => {
|
||||
user.purchased.plan.customerId = 'test-id';
|
||||
user.purchased.plan.dateTerminated = moment().add(1, 'days').toDate();
|
||||
|
||||
expect(user.hasNotCancelled()).to.be.false;
|
||||
});
|
||||
|
||||
it('returns false if user if plan.dateTerminated is before today', () => {
|
||||
user.purchased.plan.customerId = 'test-id';
|
||||
user.purchased.plan.dateTerminated = moment().subtract(1, 'days').toDate();
|
||||
|
||||
expect(user.hasNotCancelled()).to.be.false;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user