Added 90 days filter to Mrr Admin Dashboard query (#20661)

Ref https://linear.app/tryghost/issue/SLO-186/add-90-days-filter-to-mrr-admin-dashboard-query
This commit is contained in:
Princi Vershwal 2024-07-25 17:08:51 +05:30 committed by GitHub
parent b54e1ad6e7
commit 42398ce525
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 48 additions and 12 deletions

View File

@ -162,31 +162,59 @@ describe('MRR Stats Service', function () {
});
describe('fetchAllDeltas', function () {
it('Returns deltas in ascending order', async function () {
it('Returns deltas for mrr', async function () {
const ninetyDaysAgo = moment().subtract(90, 'days').startOf('day').format('YYYY-MM-DD');
const ninetyFiveDaysAgo = moment().subtract(95, 'days').startOf('day').format('YYYY-MM-DD');
const eightyNineDaysAgo = moment().subtract(89, 'days').startOf('day').format('YYYY-MM-DD');
const today = moment().startOf('day').format('YYYY-MM-DD');
await createMemberWithSubscription('month', 500, 'eur', moment(ninetyDaysAgo).toISOString());
await createMemberWithSubscription('month', 500, 'eur', moment(ninetyFiveDaysAgo).toISOString());
await createMemberWithSubscription('month', 1, 'usd', moment(eightyNineDaysAgo).toISOString());
await createMemberWithSubscription('month', 2, 'usd', moment(today).toISOString());
const results = await statsService.api.mrr.fetchAllDeltas();
results.length.should.equal(4);
results.length.should.equal(3);
results.should.match([
{
date: '2000-01-10',
date: ninetyDaysAgo,
delta: 500,
currency: 'EUR'
},
{
date: '2000-01-10',
date: eightyNineDaysAgo,
delta: 1,
currency: 'USD'
},
{
date: '2000-01-11',
delta: 1,
currency: 'USD'
},
{
date: '2000-01-12',
date: today,
delta: 2,
currency: 'USD'
}
]);
});
it('Returns deltas for the last 90 days', async function () {
const ninetyDaysAgo = moment().subtract(90, 'days').startOf('day');
const ninetyFiveDaysAgo = moment().subtract(95, 'days').startOf('day');
const eightyNineDaysAgo = moment().subtract(89, 'days').startOf('day');
const today = moment().startOf('day');
await createMemberWithSubscription('month', 500, 'eur', ninetyDaysAgo.toISOString());
await createMemberWithSubscription('month', 500, 'eur', ninetyFiveDaysAgo.toISOString());
await createMemberWithSubscription('month', 1, 'usd', eightyNineDaysAgo.toISOString());
await createMemberWithSubscription('month', 2, 'usd', today.toISOString());
const results = await statsService.api.mrr.fetchAllDeltas();
// Check that results are within the last 90 days
const isWithinLast90Days = (date) => {
return moment(date).isBetween(ninetyDaysAgo, today, null, '[]');
};
results.length.should.be.above(0);
results.forEach((result) => {
isWithinLast90Days(result.date).should.equal(true);
});
});
});
});

View File

@ -38,14 +38,15 @@ class MrrStatsService {
*/
async fetchAllDeltas() {
const knex = this.knex;
const ninetyDaysAgo = moment.utc().subtract(90, 'days').startOf('day').utc().format('YYYY-MM-DD HH:mm:ss');
const rows = await knex('members_paid_subscription_events')
.select('currency')
// In SQLite, DATE(created_at) would map to a string value, while DATE(created_at) would map to a JSDate object in MySQL
// That is why we need the cast here (to have some consistency)
.select(knex.raw('CAST(DATE(created_at) as CHAR) as date'))
.select(knex.raw(`SUM(mrr_delta) as delta`))
.groupByRaw('CAST(DATE(created_at) as CHAR), currency')
.orderByRaw('CAST(DATE(created_at) as CHAR), currency');
.where('created_at', '>=', ninetyDaysAgo)
.groupByRaw('CAST(DATE(created_at) as CHAR), currency');
return rows;
}
@ -60,6 +61,13 @@ class MrrStatsService {
const rows = await this.fetchAllDeltas();
rows.sort((rowA, rowB) => {
const dateA = new Date(rowA.date);
const dateB = new Date(rowB.date);
return dateA - dateB || rowA.currency.localeCompare(rowB.currency);
});
// Get today in UTC (default timezone)
const today = moment().format('YYYY-MM-DD');