Skip to content

Commit 02d5813

Browse files
committed
Fix invoices API to handle missing Stripe configuration
- Make Stripe initialization conditional in invoices endpoint - Add error handling for billing_events query - Wrap billing_events Firestore query in try-catch - Add billing_events index to firestore.indexes.json - Prevent API failure when Stripe or indexes not configured
1 parent 876316d commit 02d5813

3 files changed

Lines changed: 43 additions & 26 deletions

File tree

firestore.indexes.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,14 @@
9191
"fields": [
9292
{ "fieldPath": "timestamp", "order": "ASCENDING" }
9393
]
94+
},
95+
{
96+
"collectionGroup": "billing_events",
97+
"queryScope": "COLLECTION",
98+
"fields": [
99+
{ "fieldPath": "userId", "order": "ASCENDING" },
100+
{ "fieldPath": "timestamp", "order": "DESCENDING" }
101+
]
94102
}
95103
],
96104
"fieldOverrides": []

src/pages/api/payments/invoices.ts

Lines changed: 34 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,13 @@ import { NextApiRequest, NextApiResponse } from 'next';
22
import Stripe from 'stripe';
33
import { getFirestore } from '../../../utils/db';
44

5-
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY as string, {
6-
apiVersion: '2022-08-01',
7-
});
5+
// Initialize Stripe only if secret key is available
6+
let stripe: Stripe | null = null;
7+
if (process.env.STRIPE_SECRET_KEY) {
8+
stripe = new Stripe(process.env.STRIPE_SECRET_KEY, {
9+
apiVersion: '2022-08-01',
10+
});
11+
}
812

913
interface Invoice {
1014
id: string;
@@ -46,8 +50,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
4650

4751
const invoices: Invoice[] = [];
4852

49-
// If user has a Stripe customer, fetch invoices from Stripe
50-
if (stripeCustomerId) {
53+
// If user has a Stripe customer and Stripe is configured, fetch invoices from Stripe
54+
if (stripeCustomerId && stripe) {
5155
// Fetch subscription invoices from Stripe
5256
const stripeInvoices = await stripe.invoices.list({
5357
customer: stripeCustomerId,
@@ -111,26 +115,31 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
111115
}
112116

113117
// Also fetch any manual credits or adjustments from Firestore
114-
const creditsQuery = await db
115-
.collection('billing_events')
116-
.where('userId', '==', userId)
117-
.orderBy('timestamp', 'desc')
118-
.limit(Number(limit))
119-
.get();
120-
121-
creditsQuery.docs.forEach(doc => {
122-
const data = doc.data();
123-
if (data.type === 'credit' || data.type === 'adjustment') {
124-
invoices.push({
125-
id: doc.id,
126-
date: data.timestamp.toDate().toISOString(),
127-
amount: data.amount,
128-
status: 'completed',
129-
description: data.description || 'Account credit',
130-
type: 'one-time',
131-
});
132-
}
133-
});
118+
try {
119+
const creditsQuery = await db
120+
.collection('billing_events')
121+
.where('userId', '==', userId)
122+
.orderBy('timestamp', 'desc')
123+
.limit(Number(limit))
124+
.get();
125+
126+
creditsQuery.docs.forEach(doc => {
127+
const data = doc.data();
128+
if (data.type === 'credit' || data.type === 'adjustment') {
129+
invoices.push({
130+
id: doc.id,
131+
date: data.timestamp.toDate().toISOString(),
132+
amount: data.amount,
133+
status: 'completed',
134+
description: data.description || 'Account credit',
135+
type: 'one-time',
136+
});
137+
}
138+
});
139+
} catch (creditsError) {
140+
console.error('Error fetching billing events (may need Firestore index):', creditsError);
141+
// Continue without manual credits
142+
}
134143

135144
// Sort all invoices by date (most recent first)
136145
invoices.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());

tsconfig.tsbuildinfo

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)