| | import { addresses, products } from "./../../../../db/schema"; |
| | import { db } from "@/db/db"; |
| | import { carts, orders, payments } from "@/db/schema"; |
| | import { CheckoutItem } from "@/lib/types"; |
| | import { SQL, eq, inArray, sql } from "drizzle-orm"; |
| | import { headers } from "next/headers"; |
| | import { NextResponse } from "next/server"; |
| | import { Readable } from "stream"; |
| | import Stripe from "stripe"; |
| |
|
| | const endpointSecret = process.env.STRIPE_WEBHOOK_SECRET; |
| |
|
| | async function getRawBody(readable: Readable): Promise<Buffer> { |
| | const chunks = []; |
| | for await (const chunk of readable) { |
| | chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk); |
| | } |
| | return Buffer.concat(chunks); |
| | } |
| |
|
| | export async function POST(request: Request) { |
| | const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, { |
| | apiVersion: "2022-11-15", |
| | }); |
| |
|
| | const rawBody = await getRawBody(request.body as unknown as Readable); |
| |
|
| | const headersList = headers(); |
| | const sig = headersList.get("stripe-signature"); |
| | let event; |
| | try { |
| | event = stripe.webhooks.constructEvent( |
| | rawBody, |
| | sig as string, |
| | endpointSecret as string |
| | ); |
| | } catch (err: any) { |
| | return NextResponse.json( |
| | { error: `Webhook Error: ${err.message}` }, |
| | { status: 400 } |
| | ); |
| | } |
| |
|
| | let dbUpdateCartResponse; |
| | |
| | switch (event.type) { |
| | case "payment_intent.payment_failed": |
| | const paymentIntentPaymentFailed = event.data.object; |
| | |
| | break; |
| | case "payment_intent.processing": |
| | const paymentIntentProcessing = event.data.object; |
| | |
| | break; |
| | case "payment_intent.succeeded": |
| | const paymentIntentSucceeded = event.data.object; |
| | |
| | |
| |
|
| | const stripeObject = event?.data?.object as { |
| | id: string; |
| | amount: string; |
| | metadata: { |
| | cartId: string; |
| | items: string; |
| | }; |
| | shipping: { |
| | name: string; |
| | address: { |
| | line1: string; |
| | line2: string; |
| | city: string; |
| | state: string; |
| | postal_code: string; |
| | country: string; |
| | }; |
| | }; |
| | receipt_email: string; |
| | status: string; |
| | }; |
| |
|
| | const paymentIntentId = stripeObject?.id; |
| | const orderTotal = stripeObject?.amount; |
| |
|
| | try { |
| | if (!event.account) throw new Error("No account on event"); |
| | const store = await db |
| | .select({ |
| | storeId: payments.storeId, |
| | }) |
| | .from(payments) |
| | .where(eq(payments.stripeAccountId, event.account)); |
| |
|
| | const storeId = store[0].storeId as number; |
| |
|
| | |
| | const stripeAddress = stripeObject?.shipping?.address; |
| |
|
| | const newAddress = await db.insert(addresses).values({ |
| | line1: stripeAddress?.line1, |
| | line2: stripeAddress?.line2, |
| | city: stripeAddress?.city, |
| | state: stripeAddress?.state, |
| | postal_code: stripeAddress?.postal_code, |
| | country: stripeAddress?.country, |
| | }); |
| |
|
| | if (!newAddress[0].insertId) throw new Error("No address created"); |
| |
|
| | |
| | const storeOrderCount = await db |
| | .select({ count: sql<number>`count(*)` }) |
| | .from(orders) |
| | .where(eq(orders.storeId, storeId)); |
| |
|
| | |
| | const newOrder = await db.insert(orders).values({ |
| | prettyOrderId: Number(storeOrderCount[0].count) + 1, |
| | storeId: storeId, |
| | items: stripeObject.metadata?.items, |
| | total: String(Number(orderTotal) / 100), |
| | stripePaymentIntentId: paymentIntentId, |
| | stripePaymentIntentStatus: stripeObject?.status, |
| | name: stripeObject?.shipping?.name, |
| | email: stripeObject?.receipt_email, |
| | createdAt: event.created, |
| | addressId: Number(newAddress[0].insertId), |
| | }); |
| | console.log("ORDER CREATED", newOrder); |
| | } catch (err) { |
| | console.log("ORDER CREATION WEBHOOK ERROR", err); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| |
|
| | |
| | |
| | |
| |
|
| | |
| |
|
| | |
| | |
| | |
| | |
| |
|
| | try { |
| | |
| | dbUpdateCartResponse = await db |
| | .update(carts) |
| | .set({ |
| | isClosed: true, |
| | items: JSON.stringify([]), |
| | }) |
| | .where(eq(carts.paymentIntentId, paymentIntentId)); |
| | } catch (err) { |
| | console.log("WEBHOOK ERROR", err); |
| | return NextResponse.json( |
| | { response: dbUpdateCartResponse, error: err }, |
| | { status: 500 } |
| | ); |
| | } |
| |
|
| | break; |
| | |
| | default: |
| | console.log(`Unhandled event type ${event.type}`); |
| | } |
| | return NextResponse.json({ status: 200 }); |
| | } |
| |
|