fix: guard against undefined order in blueprint checkout
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,11 @@
|
||||
import { eq } from "drizzle-orm";
|
||||
import { NextResponse } from "next/server";
|
||||
import type { NextRequest } from "next/server";
|
||||
import Stripe from "stripe";
|
||||
|
||||
import { db } from "@turbostarter/db/server";
|
||||
import { blueprintOrder } from "@turbostarter/db/schema";
|
||||
|
||||
const BLUEPRINT_PRICE_CENTS = 4700;
|
||||
const CURRENCY = "eur";
|
||||
|
||||
@@ -16,10 +20,11 @@ function getStripe(): Stripe {
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const body = await request.json();
|
||||
const { email, businessName, placeId, locale } = body as {
|
||||
const { email, businessName, placeId, mapsUrl, locale } = body as {
|
||||
email: string;
|
||||
businessName: string;
|
||||
placeId: string;
|
||||
mapsUrl?: string;
|
||||
locale?: string;
|
||||
};
|
||||
|
||||
@@ -30,10 +35,87 @@ export async function POST(request: NextRequest) {
|
||||
);
|
||||
}
|
||||
|
||||
const stripe = getStripe();
|
||||
const origin = request.headers.get("origin") || process.env.NEXT_PUBLIC_URL || "http://localhost:3000";
|
||||
const origin =
|
||||
request.headers.get("origin") ||
|
||||
process.env.NEXT_PUBLIC_URL ||
|
||||
"http://localhost:3000";
|
||||
const lang = locale || "en";
|
||||
|
||||
// ── Bypass Stripe: create order + trigger engine directly ──
|
||||
if (process.env.BYPASS_STRIPE === "true") {
|
||||
const [order] = await db
|
||||
.insert(blueprintOrder)
|
||||
.values({
|
||||
email,
|
||||
businessName,
|
||||
placeId: placeId || null,
|
||||
mapsUrl: mapsUrl || null,
|
||||
language: locale || "en",
|
||||
stripeSessionId: `test_${Date.now()}`,
|
||||
status: "pending",
|
||||
})
|
||||
.returning();
|
||||
|
||||
if (!order) {
|
||||
return NextResponse.json({ error: "Failed to create order" }, { status: 500 });
|
||||
}
|
||||
|
||||
const engineUrl = process.env.ENGINE_API_URL;
|
||||
const callbackSecret = process.env.ENGINE_CALLBACK_SECRET;
|
||||
|
||||
if (!engineUrl || !callbackSecret) {
|
||||
await db
|
||||
.update(blueprintOrder)
|
||||
.set({ status: "failed", errorMessage: "ENGINE_API_URL or ENGINE_CALLBACK_SECRET not set" })
|
||||
.where(eq(blueprintOrder.id, order.id));
|
||||
return NextResponse.json(
|
||||
{ error: "Engine not configured" },
|
||||
{ status: 503 },
|
||||
);
|
||||
}
|
||||
|
||||
const publicUrl = process.env.NEXT_PUBLIC_URL || origin;
|
||||
const fulfillUrl =
|
||||
mapsUrl ||
|
||||
`https://www.google.com/maps/place/?q=place_id:${placeId}`;
|
||||
|
||||
const fulfillRes = await fetch(`${engineUrl}/api/blueprint/fulfill`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
url: fulfillUrl,
|
||||
business_name: businessName,
|
||||
place_id: placeId,
|
||||
email,
|
||||
language: locale || "en",
|
||||
callback_url: `${publicUrl}/api/webhooks/engine`,
|
||||
callback_secret: callbackSecret,
|
||||
order_id: order.id,
|
||||
}),
|
||||
});
|
||||
|
||||
if (fulfillRes.ok) {
|
||||
const data = (await fulfillRes.json()) as { job_id: string };
|
||||
await db
|
||||
.update(blueprintOrder)
|
||||
.set({ status: "processing", engineJobId: data.job_id })
|
||||
.where(eq(blueprintOrder.id, order.id));
|
||||
} else {
|
||||
const errText = await fulfillRes.text();
|
||||
await db
|
||||
.update(blueprintOrder)
|
||||
.set({ status: "failed", errorMessage: errText })
|
||||
.where(eq(blueprintOrder.id, order.id));
|
||||
}
|
||||
|
||||
// Redirect to success page with the order ID as session_id
|
||||
const successUrl = `${origin}/${lang}/get-started?step=success&session_id=${order.id}`;
|
||||
return NextResponse.json({ url: successUrl });
|
||||
}
|
||||
|
||||
// ── Normal Stripe checkout ──
|
||||
const stripe = getStripe();
|
||||
|
||||
const session = await stripe.checkout.sessions.create({
|
||||
mode: "payment",
|
||||
payment_method_types: ["card"],
|
||||
@@ -56,6 +138,8 @@ export async function POST(request: NextRequest) {
|
||||
business_name: businessName,
|
||||
place_id: placeId || "",
|
||||
email,
|
||||
maps_url: mapsUrl || "",
|
||||
language: locale || "en",
|
||||
},
|
||||
success_url: `${origin}/${lang}/get-started?step=success&session_id={CHECKOUT_SESSION_ID}`,
|
||||
cancel_url: `${origin}/${lang}/get-started?step=payment`,
|
||||
|
||||
Reference in New Issue
Block a user