mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-23 11:55:01 +03:00
✨ Added "complimentary" subscription handling (#118)
refs https://github.com/TryGhost/Ghost/pull/11537 - Adds ability to assign and cancel "complimentary" type of subscriptions to the member - The functionality is needed to be able to provide free premium plans for members (e.g. family members, trials, gifts) - When member already has an active paid subscription and complimentary one is applied the old one is upgraded. Proration is not given - When deleting a subscription we need to update localy stored records right away to be albe to reflect the change in the UI. This behavior will also be in line with how subscriptions updates/creates are handled - Blocked any client update for complimentary subscription. We should prevent non authenticated clients from upgrading/subscribing themselves to "complimentary" plan.
This commit is contained in:
parent
89b78a883d
commit
28d3a37824
@ -154,6 +154,12 @@ module.exports = function MembersApi({
|
||||
return res.end('Bad Request.');
|
||||
}
|
||||
|
||||
// NOTE: never allow "Complimenatry" plan to be subscribed to from the client
|
||||
if (plan.toLowerCase() === 'complimentary') {
|
||||
res.writeHead(400);
|
||||
return res.end('Bad Request.');
|
||||
}
|
||||
|
||||
let email;
|
||||
try {
|
||||
if (!identity) {
|
||||
@ -276,6 +282,11 @@ module.exports = function MembersApi({
|
||||
return res.end('No permission');
|
||||
}
|
||||
|
||||
if (subscription.plan.nickname === 'Complimentary') {
|
||||
res.writeHead(400);
|
||||
return res.end('Bad request');
|
||||
}
|
||||
|
||||
if (cancelAtPeriodEnd === undefined) {
|
||||
throw new common.errors.BadRequestError({
|
||||
message: 'Canceling membership failed!',
|
||||
|
@ -128,9 +128,10 @@ module.exports = class StripePaymentProcessor {
|
||||
return subscription.status !== 'canceled';
|
||||
});
|
||||
|
||||
await Promise.all(activeSubscriptions.map((subscription) => {
|
||||
return del(this._stripe, 'subscriptions', subscription.id);
|
||||
}));
|
||||
for (const subscription of activeSubscriptions) {
|
||||
const updatedSubscription = await del(this._stripe, 'subscriptions', subscription.id);
|
||||
await this._updateSubscription(updatedSubscription);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -177,6 +178,40 @@ module.exports = class StripePaymentProcessor {
|
||||
});
|
||||
}
|
||||
|
||||
async setComplimentarySubscription(member) {
|
||||
const subscriptions = await this.getActiveSubscriptions(member);
|
||||
const complimentaryPlan = this._plans.find(plan => (plan.nickname === 'Complimentary'));
|
||||
|
||||
const customer = await this._customerForMemberCheckoutSession(member);
|
||||
|
||||
if (!subscriptions.length) {
|
||||
const subscription = await create(this._stripe, 'subscriptions', {
|
||||
customer: customer.id,
|
||||
items: [{
|
||||
plan: complimentaryPlan.id
|
||||
}]
|
||||
});
|
||||
|
||||
await this._updateSubscription(subscription);
|
||||
} else {
|
||||
// NOTE: we should only ever have 1 active subscription, but just in case there is more update is done on all of them
|
||||
for (const subscription of subscriptions) {
|
||||
const updatedSubscription = await update(this._stripe, 'subscriptions', subscription.id, {
|
||||
proration_behavior: 'none',
|
||||
plan: complimentaryPlan.id
|
||||
});
|
||||
|
||||
await this._updateSubscription(updatedSubscription);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async cancelComplimentarySubscription(member) {
|
||||
// NOTE: a more explicit way would be cancelling just the "Complimentary" subscription, but doing it
|
||||
// through existing method achieves the same as there should be only one subscription at a time
|
||||
await this.cancelAllSubscriptions(member);
|
||||
}
|
||||
|
||||
async getActiveSubscriptions(member) {
|
||||
const subscriptions = await this.getSubscriptions(member);
|
||||
|
||||
|
@ -75,6 +75,18 @@ module.exports = function ({
|
||||
}
|
||||
}
|
||||
|
||||
async function setComplimentarySubscription(member) {
|
||||
if (stripe) {
|
||||
await stripe.setComplimentarySubscription(member);
|
||||
}
|
||||
}
|
||||
|
||||
async function cancelComplimentarySubscription(member) {
|
||||
if (stripe) {
|
||||
await stripe.cancelComplimentarySubscription(member);
|
||||
}
|
||||
}
|
||||
|
||||
async function get(data, options) {
|
||||
debug(`get id:${data.id} email:${data.email}`);
|
||||
const member = await getMember(data, options);
|
||||
@ -146,6 +158,8 @@ module.exports = function ({
|
||||
get,
|
||||
destroy,
|
||||
getStripeSubscriptions,
|
||||
setComplimentarySubscription,
|
||||
cancelComplimentarySubscription,
|
||||
destroyStripeSubscriptions
|
||||
};
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user