diff --git a/migrations/groups/habitrpg-jackalopes.js b/migrations/groups/habitrpg-jackalopes.js new file mode 100644 index 0000000000..de7df3eb49 --- /dev/null +++ b/migrations/groups/habitrpg-jackalopes.js @@ -0,0 +1,46 @@ +var migrationName = 'Jackalopes for Unlimited Subscribers'; + +/* + * This migration will find users with unlimited subscriptions who are also eligible for Jackalope mounts, and award them + */ +import Bluebird from 'bluebird'; + +import { model as Group } from '../../website/server/models/group'; +import { model as User } from '../../website/server/models/user'; +import * as payments from '../../website/server/libs/payments'; + +async function handOutJackalopes () { + let promises = []; + let cursor = User.find({ + 'purchased.plan.customerId':'habitrpg', + }).cursor(); + + cursor.on('data', async function(user) { + console.log('User: ' + user._id); + + let groupList = []; + if (user.party._id) groupList.push(user.party._id); + groupList = groupList.concat(user.guilds); + + let subscribedGroup = + await Group.findOne({ + '_id': {$in: groupList}, + 'purchased.plan.planId': 'group_monthly', + 'purchased.plan.dateTerminated': null, + }, + {'_id':1} + ); + + if (subscribedGroup) { + User.update({'_id':user._id},{$set:{'items.mounts.Jackalope-RoyalPurple':true}}).exec(); + promises.push(user.save()); + } + }); + + cursor.on('close', async function() { + console.log('done'); + return await Bluebird.all(promises); + }); +}; + +module.exports = handOutJackalopes; diff --git a/migrations/groups/update-groups-with-group-plans.js b/migrations/groups/update-groups-with-group-plans.js index ba9aa8e48d..f217d54031 100644 --- a/migrations/groups/update-groups-with-group-plans.js +++ b/migrations/groups/update-groups-with-group-plans.js @@ -1,30 +1,33 @@ -var migrationName = 'ResyncGroupPlanMembers'; -var authorName = 'TheHollidayInn'; // in case script author needs to know when their ... -var authorUuid = ''; //... own data is done - -/* - * This migrations will iterate through all groups with a group plan a subscription and resync the free - * subscription to all members - */ - -import Bluebird from 'bluebird'; - -import { model as Group } from '../../website/server/models/group'; -import * as payments from '../../website/server/libs/payments'; - -async function updateGroupsWithGroupPlans () { - let groups = await Group.find({ - 'purchased.plan.planId': 'group_monthly', - 'purchased.plan.dateTerminated': null, - }).exec(); - - let promises = []; - groups.forEach(function(group) { - promises.push(payments.addSubscriptionToGroupUsers(group)); - promises.push(group.save()) - }); - - return await Bluebird.all(promises); -}; - -module.exports = updateGroupsWithGroupPlans; +var migrationName = 'ResyncGroupPlanMembers'; +var authorName = 'TheHollidayInn'; // in case script author needs to know when their ... +var authorUuid = ''; //... own data is done + +/* + * This migrations will iterate through all groups with a group plan a subscription and resync the free + * subscription to all members + */ + +import Bluebird from 'bluebird'; + +import { model as Group } from '../../website/server/models/group'; +import * as payments from '../../website/server/libs/payments'; + +async function updateGroupsWithGroupPlans () { + let cursor = Group.find({ + 'purchased.plan.planId': 'group_monthly', + 'purchased.plan.dateTerminated': null, + }).cursor(); + + let promises = []; + + cursor.on('data', function(group) { + promises.push(payments.addSubscriptionToGroupUsers(group)); + promises.push(group.save()) + }); + + cursor.on('close', async function() { + return await Bluebird.all(promises); + }); +}; + +module.exports = updateGroupsWithGroupPlans; diff --git a/website/server/libs/amazonPayments.js b/website/server/libs/amazonPayments.js index 8cfb07d3ae..272b8e8445 100644 --- a/website/server/libs/amazonPayments.js +++ b/website/server/libs/amazonPayments.js @@ -196,14 +196,19 @@ api.cancelSubscription = async function cancelSubscription (options = {}) { let details = await this.getBillingAgreementDetails({ AmazonBillingAgreementId: billingAgreementId, + }).catch(function errorCatch (err) { + return err; }); - if (details.BillingAgreementDetails.BillingAgreementStatus.State !== 'Closed') { + let badBAStates = ['Canceled', 'Closed', 'Suspended']; + if (details && details.BillingAgreementDetails && details.BillingAgreementDetails.BillingAgreementStatus && + badBAStates.indexOf(details.BillingAgreementDetails.BillingAgreementStatus.State) === -1) { await this.closeBillingAgreement({ AmazonBillingAgreementId: billingAgreementId, }); } + let subscriptionBlock = common.content.subscriptionBlocks[planId]; let subscriptionLength = subscriptionBlock.months * 30; diff --git a/website/server/libs/stripePayments.js b/website/server/libs/stripePayments.js index 7aeb74ec16..3da5d71703 100644 --- a/website/server/libs/stripePayments.js +++ b/website/server/libs/stripePayments.js @@ -1,6 +1,7 @@ import stripeModule from 'stripe'; import nconf from 'nconf'; import cc from 'coupon-code'; +import moment from 'moment'; import { BadRequest, @@ -226,20 +227,27 @@ api.cancelSubscription = async function cancelSubscription (options, stripeInc) if (!customerId) throw new NotAuthorized(i18n.t('missingSubscription')); // @TODO: Handle error response - let customer = await stripeApi.customers.retrieve(customerId); + let customer = await stripeApi.customers.retrieve(customerId).catch(function errorCatch (err) { + return err; + }); + let nextBill = moment().add(30, 'days').unix() * 1000; - let subscription = customer.subscription; - if (!subscription && customer.subscriptions) { - subscription = customer.subscriptions.data[0]; + if (customer && (customer.subscription || customer.subscriptions)) { + let subscription = customer.subscription; + if (!subscription && customer.subscriptions) { + subscription = customer.subscriptions.data[0]; + } + await stripeApi.customers.del(customerId); + + if (subscription && subscription.current_period_end) { + nextBill = subscription.current_period_end * 1000; // timestamp in seconds + } } - if (!subscription) return; - - await stripeApi.customers.del(customerId); await payments.cancelSubscription({ user, groupId, - nextBill: subscription.current_period_end * 1000, // timestamp in seconds + nextBill, paymentMethod: this.constants.PAYMENT_METHOD, }); };