diff --git a/apps/web/src/app/api/blueprint/checkout/route.ts b/apps/web/src/app/api/blueprint/checkout/route.ts index 2a7ffea..082a8e9 100644 --- a/apps/web/src/app/api/blueprint/checkout/route.ts +++ b/apps/web/src/app/api/blueprint/checkout/route.ts @@ -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`,