mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-23 22:11:09 +03:00
🐛 Fixed incorrect member subscription details in Admin (#20476)
fixes https://linear.app/tryghost/issue/ENG-642 - When a subscription is in the `canceled` state the corresponding Member has no access to the Ghost site. The only time a Member will continue to have access if their subscription is due to cancel at the period end is if it is still in an active state, which is one of `active` `trialing` `unpaid` or `past_due` - When a subscription is canceled immediately (i.e. before the end of the current billing period), we now render "Ended" without a date, because we don't store the cancellation date in the subscription object. We previously used "Ended {current_period_end}" which would sometimes lead to dates in the future - Bonus: refactored code and added unit tests --------- Co-authored-by: Sag <guptazy@gmail.com>
This commit is contained in:
parent
18719e2168
commit
a4107b8202
@ -147,21 +147,7 @@
|
|||||||
{{/if}}
|
{{/if}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{#if sub.isComplimentary}}
|
<span class="gh-cp-membertier-renewal">{{sub.validityDetails}}</span>
|
||||||
{{#if sub.compExpiry}}
|
|
||||||
<span class="gh-cp-membertier-renewal">Expires {{sub.compExpiry}}</span>
|
|
||||||
{{/if}}
|
|
||||||
{{else}}
|
|
||||||
{{#if sub.hasEnded}}
|
|
||||||
<span class="gh-cp-membertier-renewal">Ended {{sub.validUntil}}</span>
|
|
||||||
{{else if sub.willEndSoon}}
|
|
||||||
<span class="gh-cp-membertier-renewal">Has access until {{sub.validUntil}}</span>
|
|
||||||
{{else if sub.trialUntil}}
|
|
||||||
<span class="gh-cp-membertier-renewal">Ends {{sub.trialUntil}}</span>
|
|
||||||
{{else}}
|
|
||||||
<span class="gh-cp-membertier-renewal">Renews {{sub.validUntil}}</span>
|
|
||||||
{{/if}}
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
</div>
|
||||||
<Member::SubscriptionDetailBox @sub={{sub}} @index={{index}} />
|
<Member::SubscriptionDetailBox @sub={{sub}} @index={{index}} />
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import Component from '@glimmer/component';
|
import Component from '@glimmer/component';
|
||||||
import moment from 'moment-timezone';
|
|
||||||
import {action} from '@ember/object';
|
import {action} from '@ember/object';
|
||||||
import {didCancel, task} from 'ember-concurrency';
|
import {didCancel, task} from 'ember-concurrency';
|
||||||
import {getNonDecimal, getSymbol} from 'ghost-admin/utils/currency';
|
import {getSubscriptionData} from 'ghost-admin/utils/subscription-data';
|
||||||
import {inject as service} from '@ember/service';
|
import {inject as service} from '@ember/service';
|
||||||
import {tracked} from '@glimmer/tracking';
|
import {tracked} from '@glimmer/tracking';
|
||||||
|
|
||||||
@ -60,41 +59,9 @@ export default class extends Component {
|
|||||||
return typeof value.id !== 'undefined' && self.findIndex(element => (element.tier_id || element.id) === (value.tier_id || value.id)) === index;
|
return typeof value.id !== 'undefined' && self.findIndex(element => (element.tier_id || element.id) === (value.tier_id || value.id)) === index;
|
||||||
});
|
});
|
||||||
|
|
||||||
let subscriptionData = subscriptions.filter((sub) => {
|
let subsWithPrice = subscriptions.filter(sub => !!sub.price);
|
||||||
return !!sub.price;
|
let subscriptionData = subsWithPrice.map(sub => getSubscriptionData(sub));
|
||||||
}).map((sub) => {
|
|
||||||
const periodEnded = sub.current_period_end && new Date(sub.current_period_end) < new Date();
|
|
||||||
const data = {
|
|
||||||
...sub,
|
|
||||||
attribution: {
|
|
||||||
...sub.attribution,
|
|
||||||
referrerSource: sub.attribution?.referrer_source || 'Unknown',
|
|
||||||
referrerMedium: sub.attribution?.referrer_medium || '-'
|
|
||||||
},
|
|
||||||
startDate: sub.start_date ? moment(sub.start_date).format('D MMM YYYY') : '-',
|
|
||||||
validUntil: sub.current_period_end ? moment(sub.current_period_end).format('D MMM YYYY') : '-',
|
|
||||||
hasEnded: sub.status === 'canceled' && periodEnded,
|
|
||||||
willEndSoon: sub.cancel_at_period_end || (sub.status === 'canceled' && !periodEnded),
|
|
||||||
cancellationReason: sub.cancellation_reason,
|
|
||||||
price: {
|
|
||||||
...sub.price,
|
|
||||||
currencySymbol: getSymbol(sub.price.currency),
|
|
||||||
nonDecimalAmount: getNonDecimal(sub.price.amount)
|
|
||||||
},
|
|
||||||
isComplimentary: !sub.id
|
|
||||||
};
|
|
||||||
if (sub.trial_end_at) {
|
|
||||||
const inTrialMode = moment(sub.trial_end_at).isAfter(new Date(), 'day');
|
|
||||||
if (inTrialMode) {
|
|
||||||
data.trialUntil = moment(sub.trial_end_at).format('D MMM YYYY');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!sub.id && sub.tier?.expiry_at) {
|
|
||||||
data.compExpiry = moment(sub.tier.expiry_at).utc().format('D MMM YYYY');
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
});
|
|
||||||
return tiers.map((tier) => {
|
return tiers.map((tier) => {
|
||||||
let tierSubscriptions = subscriptionData.filter((subscription) => {
|
let tierSubscriptions = subscriptionData.filter((subscription) => {
|
||||||
return subscription?.price?.tier?.tier_id === (tier.tier_id || tier.id);
|
return subscription?.price?.tier?.tier_id === (tier.tier_id || tier.id);
|
||||||
|
98
ghost/admin/app/utils/subscription-data.js
Normal file
98
ghost/admin/app/utils/subscription-data.js
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
import moment from 'moment-timezone';
|
||||||
|
import {getNonDecimal, getSymbol} from 'ghost-admin/utils/currency';
|
||||||
|
|
||||||
|
export function getSubscriptionData(sub) {
|
||||||
|
const data = {
|
||||||
|
...sub,
|
||||||
|
attribution: {
|
||||||
|
...sub.attribution,
|
||||||
|
referrerSource: sub.attribution?.referrer_source || 'Unknown',
|
||||||
|
referrerMedium: sub.attribution?.referrer_medium || '-'
|
||||||
|
},
|
||||||
|
startDate: sub.start_date ? moment(sub.start_date).format('D MMM YYYY') : '-',
|
||||||
|
validUntil: validUntil(sub),
|
||||||
|
hasEnded: isCanceled(sub),
|
||||||
|
willEndSoon: isSetToCancel(sub),
|
||||||
|
cancellationReason: sub.cancellation_reason,
|
||||||
|
price: {
|
||||||
|
...sub.price,
|
||||||
|
currencySymbol: getSymbol(sub.price.currency),
|
||||||
|
nonDecimalAmount: getNonDecimal(sub.price.amount)
|
||||||
|
},
|
||||||
|
isComplimentary: isComplimentary(sub),
|
||||||
|
compExpiry: compExpiry(sub),
|
||||||
|
trialUntil: trialUntil(sub)
|
||||||
|
};
|
||||||
|
|
||||||
|
data.validityDetails = validityDetails(data);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function validUntil(sub) {
|
||||||
|
// If a subscription has been canceled immediately, don't render the end of validity date
|
||||||
|
// Reason: we don't store the exact cancelation date in the subscription object
|
||||||
|
if (sub.status === 'canceled' && !sub.cancel_at_period_end) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, show the current period end date
|
||||||
|
if (sub.current_period_end) {
|
||||||
|
return moment(sub.current_period_end).format('D MMM YYYY');
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isActive(sub) {
|
||||||
|
return ['active', 'trialing', 'past_due', 'unpaid'].includes(sub.status);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isComplimentary(sub) {
|
||||||
|
return !sub.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isCanceled(sub) {
|
||||||
|
return sub.status === 'canceled';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isSetToCancel(sub) {
|
||||||
|
return sub.cancel_at_period_end && isActive(sub);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function compExpiry(sub) {
|
||||||
|
if (!sub.id && sub.tier && sub.tier.expiry_at) {
|
||||||
|
return moment(sub.tier.expiry_at).utc().format('D MMM YYYY');
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function trialUntil(sub) {
|
||||||
|
const inTrialMode = sub.trial_end_at && moment(sub.trial_end_at).isAfter(new Date(), 'day');
|
||||||
|
if (inTrialMode) {
|
||||||
|
return moment(sub.trial_end_at).format('D MMM YYYY');
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function validityDetails(data) {
|
||||||
|
if (data.isComplimentary && data.compExpiry) {
|
||||||
|
return `Expires ${data.compExpiry}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.hasEnded) {
|
||||||
|
return `Ended ${data.validUntil}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.willEndSoon) {
|
||||||
|
return `Has access until ${data.validUntil}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.trialUntil) {
|
||||||
|
return `Ends ${data.trialUntil}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `Renews ${data.validUntil}`;
|
||||||
|
}
|
341
ghost/admin/tests/unit/utils/subscription-data-test.js
Normal file
341
ghost/admin/tests/unit/utils/subscription-data-test.js
Normal file
@ -0,0 +1,341 @@
|
|||||||
|
import moment from 'moment-timezone';
|
||||||
|
import {compExpiry, getSubscriptionData, isActive, isCanceled, isComplimentary, isSetToCancel, trialUntil, validUntil, validityDetails} from 'ghost-admin/utils/subscription-data';
|
||||||
|
import {describe, it} from 'mocha';
|
||||||
|
import {expect} from 'chai';
|
||||||
|
|
||||||
|
describe.only('Unit: Util: subscription-data', function () {
|
||||||
|
describe('validUntil', function () {
|
||||||
|
it('returns the end of the current billing period when the subscription is canceled at the end of the period', function () {
|
||||||
|
let sub = {
|
||||||
|
status: 'canceled',
|
||||||
|
cancel_at_period_end: true,
|
||||||
|
current_period_end: '2021-05-31'
|
||||||
|
};
|
||||||
|
expect(validUntil(sub)).to.equal('31 May 2021');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns an empty string when the subscription is canceled immediately', function () {
|
||||||
|
let sub = {
|
||||||
|
status: 'canceled',
|
||||||
|
cancel_at_period_end: false,
|
||||||
|
current_period_end: '2021-05-31'
|
||||||
|
};
|
||||||
|
expect(validUntil(sub)).to.equal('');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns the end of the current billing period when the subscription is active', function () {
|
||||||
|
let sub = {
|
||||||
|
status: 'active',
|
||||||
|
cancel_at_period_end: false,
|
||||||
|
current_period_end: '2021-05-31'
|
||||||
|
};
|
||||||
|
expect(validUntil(sub)).to.equal('31 May 2021');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns the end of the current billing period when the subscription is in trial', function () {
|
||||||
|
let sub = {
|
||||||
|
status: 'trialing',
|
||||||
|
cancel_at_period_end: false,
|
||||||
|
current_period_end: '2021-05-31'
|
||||||
|
};
|
||||||
|
expect(validUntil(sub)).to.equal('31 May 2021');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns the end of the current billing period when the subscription is past_due', function () {
|
||||||
|
let sub = {
|
||||||
|
status: 'past_due',
|
||||||
|
cancel_at_period_end: false,
|
||||||
|
current_period_end: '2021-05-31'
|
||||||
|
};
|
||||||
|
expect(validUntil(sub)).to.equal('31 May 2021');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns the end of the current billing period when the subscription is unpaid', function () {
|
||||||
|
let sub = {
|
||||||
|
status: 'unpaid',
|
||||||
|
cancel_at_period_end: false,
|
||||||
|
current_period_end: '2021-05-31'
|
||||||
|
};
|
||||||
|
expect(validUntil(sub)).to.equal('31 May 2021');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Extra data safety check, mainly for imported subscriptions
|
||||||
|
it('returns an empty string if the subcription is canceled immediately and has no current_period_start', function () {
|
||||||
|
let sub = {
|
||||||
|
status: 'canceled',
|
||||||
|
cancel_at_period_end: false
|
||||||
|
};
|
||||||
|
expect(validUntil(sub)).to.equal('');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Extra data safety check, mainly for imported subscriptions
|
||||||
|
it('returns an empty string if the subscription has no current_period_end', function () {
|
||||||
|
let sub = {
|
||||||
|
status: 'active',
|
||||||
|
cancel_at_period_end: false
|
||||||
|
};
|
||||||
|
expect(validUntil(sub)).to.equal('');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('isActive', function () {
|
||||||
|
it('returns true for active subscriptions', function () {
|
||||||
|
let sub = {status: 'active'};
|
||||||
|
expect(isActive(sub)).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns true for trialing subscriptions', function () {
|
||||||
|
let sub = {status: 'trialing'};
|
||||||
|
expect(isActive(sub)).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns true for past_due subscriptions', function () {
|
||||||
|
let sub = {status: 'past_due'};
|
||||||
|
expect(isActive(sub)).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns true for unpaid subscriptions', function () {
|
||||||
|
let sub = {status: 'unpaid'};
|
||||||
|
expect(isActive(sub)).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns false for canceled subscriptions', function () {
|
||||||
|
let sub = {status: 'canceled'};
|
||||||
|
expect(isActive(sub)).to.be.false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('isComplimentary', function () {
|
||||||
|
it('returns true for complimentary subscriptions', function () {
|
||||||
|
let sub = {id: null};
|
||||||
|
expect(isComplimentary(sub)).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns false for paid subscriptions', function () {
|
||||||
|
let sub = {id: 'sub_123'};
|
||||||
|
expect(isComplimentary(sub)).to.be.false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('isCanceled', function () {
|
||||||
|
it('returns true for canceled subscriptions', function () {
|
||||||
|
let sub = {status: 'canceled'};
|
||||||
|
expect(isCanceled(sub)).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns false for active subscriptions', function () {
|
||||||
|
let sub = {status: 'active'};
|
||||||
|
expect(isCanceled(sub)).to.be.false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('isSetToCancel', function () {
|
||||||
|
it('returns true for subscriptions set to cancel at the end of the period', function () {
|
||||||
|
let sub = {status: 'active', cancel_at_period_end: true};
|
||||||
|
expect(isSetToCancel(sub)).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns false for canceled subscriptions', function () {
|
||||||
|
let sub = {status: 'canceled', cancel_at_period_end: true};
|
||||||
|
expect(isSetToCancel(sub)).to.be.false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('trialUntil', function () {
|
||||||
|
it('returns the trial end date for subscriptions in trial', function () {
|
||||||
|
let sub = {status: 'trialing', trial_end_at: '2222-05-31'};
|
||||||
|
expect(trialUntil(sub)).to.equal('31 May 2222');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns undefined for subscriptions not in trial', function () {
|
||||||
|
let sub = {status: 'active'};
|
||||||
|
expect(trialUntil(sub)).to.be.undefined;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('compExpiry', function () {
|
||||||
|
it('returns the complimentary expiry date for complimentary subscriptions', function () {
|
||||||
|
let sub = {id: null, tier: {expiry_at: moment.utc('2021-05-31').toISOString()}};
|
||||||
|
expect(compExpiry(sub)).to.equal('31 May 2021');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns undefined for paid subscriptions', function () {
|
||||||
|
let sub = {id: 'sub_123'};
|
||||||
|
expect(compExpiry(sub)).to.be.undefined;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('validityDetails', function () {
|
||||||
|
it('returns "Expires {compExpiry}" for expired complimentary subscriptions', function () {
|
||||||
|
let data = {
|
||||||
|
isComplimentary: true,
|
||||||
|
compExpiry: '31 May 2021'
|
||||||
|
};
|
||||||
|
expect(validityDetails(data)).to.equal('Expires 31 May 2021');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns "Ended {validUntil}" for canceled subscriptions', function () {
|
||||||
|
let data = {
|
||||||
|
hasEnded: true,
|
||||||
|
validUntil: '31 May 2021'
|
||||||
|
};
|
||||||
|
expect(validityDetails(data)).to.equal('Ended 31 May 2021');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns "Has access until {validUntil}" for set to cancel subscriptions', function () {
|
||||||
|
let data = {
|
||||||
|
willEndSoon: true,
|
||||||
|
validUntil: '31 May 2021'
|
||||||
|
};
|
||||||
|
expect(validityDetails(data)).to.equal('Has access until 31 May 2021');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns "Ends {validUntil}" for trial subscriptions', function () {
|
||||||
|
let data = {
|
||||||
|
trialUntil: '31 May 2021'
|
||||||
|
};
|
||||||
|
expect(validityDetails(data)).to.equal('Ends 31 May 2021');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns "Renews {validUntil}" for active subscriptions', function () {
|
||||||
|
let data = {
|
||||||
|
validUntil: '31 May 2021'
|
||||||
|
};
|
||||||
|
expect(validityDetails(data)).to.equal('Renews 31 May 2021');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getSubscriptionData', function () {
|
||||||
|
it('returns the correct data for an active subscription', function () {
|
||||||
|
let sub = {
|
||||||
|
id: 'defined',
|
||||||
|
status: 'active',
|
||||||
|
cancel_at_period_end: false,
|
||||||
|
current_period_end: '2021-05-31',
|
||||||
|
trial_end_at: null,
|
||||||
|
tier: null,
|
||||||
|
price: {
|
||||||
|
currency: 'usd',
|
||||||
|
amount: 5000
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let data = getSubscriptionData(sub);
|
||||||
|
|
||||||
|
expect(data).to.include({
|
||||||
|
isComplimentary: false,
|
||||||
|
compExpiry: undefined,
|
||||||
|
hasEnded: false,
|
||||||
|
validUntil: '31 May 2021',
|
||||||
|
willEndSoon: false,
|
||||||
|
trialUntil: undefined,
|
||||||
|
validityDetails: 'Renews 31 May 2021'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns the correct data for a trial subscription', function () {
|
||||||
|
let sub = {
|
||||||
|
id: 'defined',
|
||||||
|
status: 'trialing',
|
||||||
|
cancel_at_period_end: false,
|
||||||
|
current_period_end: '2222-05-31',
|
||||||
|
trial_end_at: '2222-05-31',
|
||||||
|
tier: null,
|
||||||
|
price: {
|
||||||
|
currency: 'usd',
|
||||||
|
amount: 5000
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let data = getSubscriptionData(sub);
|
||||||
|
|
||||||
|
expect(data).to.include({
|
||||||
|
isComplimentary: false,
|
||||||
|
compExpiry: undefined,
|
||||||
|
hasEnded: false,
|
||||||
|
validUntil: '31 May 2222',
|
||||||
|
willEndSoon: false,
|
||||||
|
trialUntil: '31 May 2222',
|
||||||
|
validityDetails: 'Ends 31 May 2222'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns the correct data for an immediately canceled subscription', function () {
|
||||||
|
let sub = {
|
||||||
|
id: 'defined',
|
||||||
|
status: 'canceled',
|
||||||
|
cancel_at_period_end: false,
|
||||||
|
current_period_end: '2021-05-31',
|
||||||
|
trial_end_at: null,
|
||||||
|
tier: null,
|
||||||
|
price: {
|
||||||
|
currency: 'usd',
|
||||||
|
amount: 5000
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let data = getSubscriptionData(sub);
|
||||||
|
|
||||||
|
expect(data).to.include({
|
||||||
|
isComplimentary: false,
|
||||||
|
compExpiry: undefined,
|
||||||
|
hasEnded: true,
|
||||||
|
validUntil: '',
|
||||||
|
willEndSoon: false,
|
||||||
|
trialUntil: undefined,
|
||||||
|
validityDetails: 'Ended '
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns the correct data for a subscription set to cancel at the end of the period', function () {
|
||||||
|
let sub = {
|
||||||
|
id: 'defined',
|
||||||
|
status: 'active',
|
||||||
|
cancel_at_period_end: true,
|
||||||
|
current_period_end: '2021-05-31',
|
||||||
|
trial_end_at: null,
|
||||||
|
tier: null,
|
||||||
|
price: {
|
||||||
|
currency: 'usd',
|
||||||
|
amount: 5000
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let data = getSubscriptionData(sub);
|
||||||
|
|
||||||
|
expect(data).to.include({
|
||||||
|
isComplimentary: false,
|
||||||
|
compExpiry: undefined,
|
||||||
|
hasEnded: false,
|
||||||
|
validUntil: '31 May 2021',
|
||||||
|
willEndSoon: true,
|
||||||
|
trialUntil: undefined,
|
||||||
|
validityDetails: 'Has access until 31 May 2021'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns the correct data for a complimentary subscription', function () {
|
||||||
|
let sub = {
|
||||||
|
id: null,
|
||||||
|
status: 'active',
|
||||||
|
cancel_at_period_end: false,
|
||||||
|
current_period_end: '2021-05-31',
|
||||||
|
trial_end_at: null,
|
||||||
|
tier: {
|
||||||
|
expiry_at: moment.utc('2021-05-31').toISOString()
|
||||||
|
},
|
||||||
|
price: {
|
||||||
|
currency: 'usd',
|
||||||
|
amount: 0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let data = getSubscriptionData(sub);
|
||||||
|
|
||||||
|
expect(data).to.include({
|
||||||
|
isComplimentary: true,
|
||||||
|
compExpiry: '31 May 2021',
|
||||||
|
hasEnded: false,
|
||||||
|
validUntil: '31 May 2021',
|
||||||
|
willEndSoon: false,
|
||||||
|
trialUntil: undefined,
|
||||||
|
validityDetails: 'Expires 31 May 2021'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user