Skip to content

Commit d79ae15

Browse files
committed
refactor(webhook): Improve invoice creation handler with better error handling
Split invoice processing into smaller, focused functions: - Extract finalizeAndPayInvoice into separate function - Add early return for non-canceled subscriptions - Improve code organization with clear responsibility separation This refactor enhances error handling and makes the code more maintainable by following single responsibility principle.
1 parent 1bcb884 commit d79ae15

File tree

2 files changed

+32
-29
lines changed

2 files changed

+32
-29
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { stripe } from "@/services/external/stripe";
2+
import type Stripe from "stripe";
3+
4+
export async function handleInvoiceCreation(invoice: Stripe.Invoice) {
5+
if (!invoice.subscription || typeof invoice.subscription !== "string") {
6+
throw new Error(
7+
"Invoice is missing a subscription ID. Please check the invoice data.",
8+
);
9+
}
10+
11+
const subscription = await stripe.subscriptions.retrieve(
12+
invoice.subscription,
13+
);
14+
15+
if (subscription.status !== "canceled") {
16+
return;
17+
}
18+
19+
await finalizeAndPayInvoice(invoice.id);
20+
}
21+
22+
async function finalizeAndPayInvoice(invoiceId: string) {
23+
try {
24+
await stripe.invoices.finalizeInvoice(invoiceId);
25+
await stripe.invoices.pay(invoiceId);
26+
} catch (error) {
27+
console.error(`Error processing invoice ${invoiceId}:`, error);
28+
throw new Error("Failed to process invoice");
29+
}
30+
}

app/webhooks/stripe/route.ts

+2-29
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { stripe } from "@/services/external/stripe";
22
import { upsertSubscription } from "@/services/external/stripe/actions/upsert-subscription";
33
import type Stripe from "stripe";
4+
import { handleInvoiceCreation } from "./handle-invoice-creation";
45
import { handleSubscriptionCancellation } from "./handle-subscription-cancellation";
56
import { handleSubscriptionCycleInvoice } from "./handle-subscription-cycle-invoice";
67

@@ -85,35 +86,7 @@ export async function POST(req: Request) {
8586
break;
8687

8788
case "invoice.created": {
88-
console.log(`🔔 Invoice created: ${event.data.object.id}`);
89-
90-
const invoice = event.data.object;
91-
92-
if (!invoice.subscription || typeof invoice.subscription !== "string") {
93-
throw new Error(
94-
"Invoice is missing a subscription ID. Please check the invoice data.",
95-
);
96-
}
97-
98-
const subscription = await stripe.subscriptions.retrieve(
99-
invoice.subscription,
100-
);
101-
102-
if (subscription.status === "canceled") {
103-
try {
104-
await stripe.invoices.finalizeInvoice(invoice.id);
105-
} catch (error) {
106-
console.error(`Error finalizing invoice ${invoice.id}:`, error);
107-
throw new Error("Failed to finalize invoice.");
108-
}
109-
110-
try {
111-
await stripe.invoices.pay(invoice.id);
112-
} catch (error) {
113-
console.error(`Error paying invoice ${invoice.id}:`, error);
114-
throw new Error("Failed to pay invoice.");
115-
}
116-
}
89+
await handleInvoiceCreation(event.data.object);
11790

11891
// TODO: This block will be removed in the other issue.
11992
if (event.data.object.billing_reason === "subscription_cycle") {

0 commit comments

Comments
 (0)