feat: migrate getRevenueStats to fetch directly from Stripe API with database fallback
This commit is contained in:
@@ -1,12 +1,16 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { PrismaService } from '../prisma/prisma.service';
|
||||
import { SubscriptionStatus } from '@prisma/client';
|
||||
import { StripeService } from './stripe.service';
|
||||
|
||||
@Injectable()
|
||||
export class SubscriptionService {
|
||||
private readonly logger = new Logger(SubscriptionService.name);
|
||||
|
||||
constructor(private prisma: PrismaService) {}
|
||||
constructor(
|
||||
private prisma: PrismaService,
|
||||
private stripeService: StripeService,
|
||||
) {}
|
||||
|
||||
async getActivePlan(userId: string) {
|
||||
return this.prisma.agentSubscription.findFirst({
|
||||
@@ -129,6 +133,73 @@ export class SubscriptionService {
|
||||
}
|
||||
|
||||
async getRevenueStats() {
|
||||
try {
|
||||
const stripe = this.stripeService.getStripe();
|
||||
|
||||
// Count active subscriptions from Stripe
|
||||
let activeCount = 0;
|
||||
let hasMore = true;
|
||||
let startingAfter: string | undefined;
|
||||
while (hasMore) {
|
||||
const subs = await stripe.subscriptions.list({
|
||||
status: 'active',
|
||||
limit: 100,
|
||||
...(startingAfter ? { starting_after: startingAfter } : {}),
|
||||
});
|
||||
activeCount += subs.data.length;
|
||||
hasMore = subs.has_more;
|
||||
if (subs.data.length > 0) {
|
||||
startingAfter = subs.data[subs.data.length - 1].id;
|
||||
}
|
||||
}
|
||||
|
||||
// Total revenue: sum of all successful charges
|
||||
let totalRevenueCents = 0;
|
||||
hasMore = true;
|
||||
startingAfter = undefined;
|
||||
while (hasMore) {
|
||||
const charges = await stripe.charges.list({
|
||||
limit: 100,
|
||||
...(startingAfter ? { starting_after: startingAfter } : {}),
|
||||
});
|
||||
totalRevenueCents += charges.data
|
||||
.filter((c) => c.status === 'succeeded')
|
||||
.reduce((sum, c) => sum + c.amount, 0);
|
||||
hasMore = charges.has_more;
|
||||
if (charges.data.length > 0) {
|
||||
startingAfter = charges.data[charges.data.length - 1].id;
|
||||
}
|
||||
}
|
||||
|
||||
// Monthly revenue: charges from start of current month
|
||||
const monthStart = new Date(new Date().getFullYear(), new Date().getMonth(), 1);
|
||||
let monthlyRevenueCents = 0;
|
||||
hasMore = true;
|
||||
startingAfter = undefined;
|
||||
while (hasMore) {
|
||||
const charges = await stripe.charges.list({
|
||||
limit: 100,
|
||||
created: { gte: Math.floor(monthStart.getTime() / 1000) },
|
||||
...(startingAfter ? { starting_after: startingAfter } : {}),
|
||||
});
|
||||
monthlyRevenueCents += charges.data
|
||||
.filter((c) => c.status === 'succeeded')
|
||||
.reduce((sum, c) => sum + c.amount, 0);
|
||||
hasMore = charges.has_more;
|
||||
if (charges.data.length > 0) {
|
||||
startingAfter = charges.data[charges.data.length - 1].id;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
activeSubscriptions: activeCount,
|
||||
totalRevenue: totalRevenueCents / 100,
|
||||
monthlyRevenue: monthlyRevenueCents / 100,
|
||||
};
|
||||
} catch (error) {
|
||||
this.logger.warn(`Failed to fetch stats from Stripe, falling back to DB: ${error.message}`);
|
||||
|
||||
// Fallback to local DB
|
||||
const [activeCount, totalRevenue, monthlyRevenue] = await Promise.all([
|
||||
this.prisma.agentSubscription.count({ where: { status: 'ACTIVE' } }),
|
||||
this.prisma.payment.aggregate({
|
||||
@@ -152,6 +223,7 @@ export class SubscriptionService {
|
||||
monthlyRevenue: (monthlyRevenue._sum.amount || 0) / 100,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private async updateAgentSubscriptionStatus(userId: string, status: SubscriptionStatus) {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user