Skip to content

Commit

Permalink
refactor(webhook): Improve invoice creation handler with better error…
Browse files Browse the repository at this point in the history
… 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.
  • Loading branch information
gentamura committed Jan 7, 2025
1 parent 1bcb884 commit edfa1aa
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 28 deletions.
30 changes: 30 additions & 0 deletions app/webhooks/stripe/handle-invoice-creation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { stripe } from "@/services/external/stripe";
import type Stripe from "stripe";

export async function handleInvoiceCreation(invoice: Stripe.Invoice) {
if (!invoice.subscription || typeof invoice.subscription !== "string") {
throw new Error(
"Invoice is missing a subscription ID. Please check the invoice data.",
);
}

const subscription = await stripe.subscriptions.retrieve(
invoice.subscription,
);

if (subscription.status !== "canceled") {
return;
}

await finalizeAndPayInvoice(invoice.id);
}

async function finalizeAndPayInvoice(invoiceId: string) {
try {
await stripe.invoices.finalizeInvoice(invoiceId);
await stripe.invoices.pay(invoiceId);
} catch (error) {
console.error(`Error processing invoice ${invoiceId}:`, error);
throw new Error("Failed to process invoice");
}
}
31 changes: 3 additions & 28 deletions app/webhooks/stripe/route.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { stripe } from "@/services/external/stripe";
import { upsertSubscription } from "@/services/external/stripe/actions/upsert-subscription";
import type Stripe from "stripe";
import { handleInvoiceCreation } from "./handle-invoice-creation";
import { handleSubscriptionCancellation } from "./handle-subscription-cancellation";
import { handleSubscriptionCycleInvoice } from "./handle-subscription-cycle-invoice";

Expand Down Expand Up @@ -85,35 +86,9 @@ export async function POST(req: Request) {
break;

case "invoice.created": {
console.log(`🔔 Invoice created: ${event.data.object.id}`);
console.log(`🔔 Invoice created: ${event.data.object.id}`);

const invoice = event.data.object;

if (!invoice.subscription || typeof invoice.subscription !== "string") {
throw new Error(
"Invoice is missing a subscription ID. Please check the invoice data.",
);
}

const subscription = await stripe.subscriptions.retrieve(
invoice.subscription,
);

if (subscription.status === "canceled") {
try {
await stripe.invoices.finalizeInvoice(invoice.id);
} catch (error) {
console.error(`Error finalizing invoice ${invoice.id}:`, error);
throw new Error("Failed to finalize invoice.");
}

try {
await stripe.invoices.pay(invoice.id);
} catch (error) {
console.error(`Error paying invoice ${invoice.id}:`, error);
throw new Error("Failed to pay invoice.");
}
}
await handleInvoiceCreation(event.data.object);

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

0 comments on commit edfa1aa

Please sign in to comment.