Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 15x 15x 15x 15x 15x 15x 15x 15x 15x 15x 4x 4x 11x 11x 11x 11x 11x 11x 11x 11x 11x 11x 11x 11x 11x 11x 10x 15x 1x 1x 1x 9x 15x 1x 1x 1x 1x 1x 1x 8x 8x 8x 8x 8x 8x 8x 15x 1x 1x 1x 1x 1x 7x 7x 7x 7x 7x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 1x 1x 8x 8x 8x 8x 8x 8x 8x 8x 8x 1x 1x | import { NextRequest, NextResponse } from 'next/server';
import {
withAuth,
withErrorHandling,
successResponse,
ApiError,
ApiSuccessResponse,
ApiErrorResponse } from "@/lib/api";
import { RouteContext } from "@/lib/api/middleware";
import { prisma } from "@/lib/prisma";
import { logger } from "@/lib/logging";
import { z } from "zod";
import { Session } from "next-auth";
import { Order } from "@prisma/client";
// Payment schema
const PaymentSchema = z.object({
orderId: z.number(),
amount: z.number().positive(),
paymentMethod: z.enum(["credit_card", "paypal", "apple_pay"]),
cardToken: z.string().optional(), // Stripe token or similar
});
// Response type
interface PaymentResponse {
message: string;
order: Order;
}
// POST /api/payments - Process payment
async function handlePost(
request: NextRequest,
_context: RouteContext | undefined,
session: Session
): Promise<NextResponse<ApiSuccessResponse<PaymentResponse> | ApiErrorResponse>> {
const body = await request.json();
// Validate input
const validationResult = PaymentSchema.safeParse(body);
if (!validationResult.success) {
throw ApiError.validation("Invalid payment data", validationResult.error.issues);
}
const validatedData = validationResult.data;
const paymentLogger = logger.child({
category: 'PAYMENT',
orderId: validatedData.orderId,
userId: session.user.id,
amount: validatedData.amount,
});
paymentLogger.info('Processing payment');
// Verify order exists and belongs to user
const order = await prisma.order.findUnique({
where: { id: validatedData.orderId }});
if (!order) {
paymentLogger.warn('Order not found for payment');
throw ApiError.notFound("Order", validatedData.orderId);
}
if (order.userId !== session.user.id) {
paymentLogger.security('Unauthorized payment attempt', {
orderOwnerId: order.userId,
attemptedBy: session.user.id,
}, 'high');
throw ApiError.forbidden("You do not have access to this order");
}
// TODO: Integrate with Stripe or payment provider
// For now, we'll simulate successful payment
const paymentSuccessful = await simulatePayment(
validatedData.amount
);
if (!paymentSuccessful) {
paymentLogger.error('Payment processing failed', undefined, {
paymentMethod: validatedData.paymentMethod,
});
throw ApiError.paymentFailed("Payment processing failed");
}
// Update order status
const updatedOrder = await prisma.order.update({
where: { id: validatedData.orderId },
data: { status: "SHIPPED" }});
paymentLogger.business('PaymentCompleted', {
orderId: validatedData.orderId,
amount: validatedData.amount,
paymentMethod: validatedData.paymentMethod,
});
return successResponse({
message: "Payment processed successfully",
order: updatedOrder});
}
// Simulate payment processing
async function simulatePayment(
amount: number
): Promise<boolean> {
// In a real scenario, this would call Stripe API or similar
// For now, we'll simulate based on amount
// Amounts ending in 00 are considered successful
// This is just for testing
return Math.round(amount * 100) % 100 === 0;
}
export const POST = withErrorHandling(withAuth(handlePost));
|