🐛 Fixed plan upgrade not cancelling trial (#18699)
closes https://github.com/TryGhost/Product/issues/4036 Fixed a bug where a member on a trial plan would not have their trial cancelled when they upgraded to a paid plan
This commit is contained in:
parent
93382df314
commit
094ea1d2b0
@ -556,15 +556,7 @@ export function subscriptionHasFreeTrial({sub} = {}) {
|
||||
}
|
||||
|
||||
export function isInThePast(date) {
|
||||
const today = new Date();
|
||||
|
||||
// 👇️ OPTIONAL!
|
||||
// This line sets the hour of the current date to midnight
|
||||
// so the comparison only returns `true` if the passed in date
|
||||
// is at least yesterday
|
||||
today.setHours(0, 0, 0, 0);
|
||||
|
||||
return date < today;
|
||||
return date < new Date();
|
||||
}
|
||||
|
||||
export function getProductFromPrice({site, priceId}) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {getAllProductsForSite, getAvailableProducts, getCurrencySymbol, getFreeProduct, getMemberName, getMemberSubscription, getPriceFromSubscription, getPriceIdFromPageQuery, getSupportAddress, getUrlHistory, hasMultipleProducts, isActiveOffer, isInviteOnlySite, isPaidMember, isSameCurrency, transformApiTiersData, isSigninAllowed, isSignupAllowed, getCompExpiry} from './helpers';
|
||||
import {getAllProductsForSite, getAvailableProducts, getCurrencySymbol, getFreeProduct, getMemberName, getMemberSubscription, getPriceFromSubscription, getPriceIdFromPageQuery, getSupportAddress, getUrlHistory, hasMultipleProducts, isActiveOffer, isInviteOnlySite, isPaidMember, isSameCurrency, transformApiTiersData, isSigninAllowed, isSignupAllowed, getCompExpiry, isInThePast} from './helpers';
|
||||
import * as Fixtures from './fixtures-generator';
|
||||
import {site as FixturesSite, member as FixtureMember, offer as FixtureOffer, transformTierFixture as TransformFixtureTiers} from '../utils/test-fixtures';
|
||||
import {isComplimentaryMember} from '../utils/helpers';
|
||||
@ -448,4 +448,17 @@ describe('Helpers - ', () => {
|
||||
expect(getCompExpiry({member})).toEqual('');
|
||||
});
|
||||
});
|
||||
|
||||
describe('isInThePast', () => {
|
||||
it('returns a boolean indicating if the provided date is in the past', () => {
|
||||
const pastDate = new Date();
|
||||
pastDate.setDate(pastDate.getDate() - 1);
|
||||
|
||||
const futureDate = new Date();
|
||||
futureDate.setDate(futureDate.getDate() + 1);
|
||||
|
||||
expect(isInThePast(pastDate)).toEqual(true);
|
||||
expect(isInThePast(futureDate)).toEqual(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -21,6 +21,8 @@ const messages = {
|
||||
invalidEmail: 'Invalid Email'
|
||||
};
|
||||
|
||||
const SUBSCRIPTION_STATUS_TRIALING = 'trialing';
|
||||
|
||||
/**
|
||||
* @typedef {object} ITokenService
|
||||
* @prop {(token: string) => Promise<import('jsonwebtoken').JwtPayload>} decodeToken
|
||||
@ -1367,6 +1369,10 @@ module.exports = class MemberRepository {
|
||||
data.subscription.price
|
||||
);
|
||||
updatedSubscription = await this._stripeAPIService.removeCouponFromSubscription(subscription.id);
|
||||
|
||||
if (subscriptionModel.get('status') === SUBSCRIPTION_STATUS_TRIALING) {
|
||||
updatedSubscription = await this._stripeAPIService.cancelSubscriptionTrial(subscription.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -759,4 +759,16 @@ module.exports = class StripeAPI {
|
||||
default_payment_method: paymentMethod
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} id - The ID of the subscription to cancel the trial for
|
||||
*
|
||||
* @returns {Promise<import('stripe').Stripe.Subscription>}
|
||||
*/
|
||||
async cancelSubscriptionTrial(id) {
|
||||
await this._rateLimitBucket.throttle();
|
||||
return this._stripe.subscriptions.update(id, {
|
||||
trial_end: 'now'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -250,4 +250,37 @@ describe('StripeAPI', function () {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('cancelSubscriptionTrial', function () {
|
||||
const mockSubscription = {
|
||||
id: 'sub_123'
|
||||
};
|
||||
beforeEach(function () {
|
||||
mockStripe = {
|
||||
subscriptions: {
|
||||
update: sinon.stub().resolves(mockSubscription)
|
||||
}
|
||||
};
|
||||
const mockStripeConstructor = sinon.stub().returns(mockStripe);
|
||||
StripeAPI.__set__('Stripe', mockStripeConstructor);
|
||||
api.configure({
|
||||
secretKey: ''
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
it('cancels a subscription trial', async function () {
|
||||
const result = await api.cancelSubscriptionTrial(mockSubscription.id);
|
||||
|
||||
should.equal(mockStripe.subscriptions.update.callCount, 1);
|
||||
|
||||
should.equal(mockStripe.subscriptions.update.args[0][0], mockSubscription.id);
|
||||
should.deepEqual(mockStripe.subscriptions.update.args[0][1], {trial_end: 'now'});
|
||||
|
||||
should.deepEqual(result, mockSubscription);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user