All files / src/app/api/promotions/applicable route.ts

100% Statements 78/78
88.23% Branches 15/17
100% Functions 1/1
100% Lines 78/78

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 791x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 9x 9x 9x 9x 9x 9x 9x 1x 1x 1x 1x 1x 9x 9x 9x 9x 9x 2x 2x 2x 2x 7x 7x 7x 14x 14x 14x 14x 7x 7x 7x 7x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 1x 1x  
export const dynamic = "force-dynamic";
 
import { NextRequest, NextResponse } from 'next/server';
import { auth } from "@/lib/auth/auth";
import { prisma } from "@/lib/prisma";
import { promotionEngine } from "@/lib/promotions";
import {
  withErrorHandling,
  successResponse,
  ApiSuccessResponse,
  ApiErrorResponse } from "@/lib/api";
import type { CartItem } from "@/lib/promotions/types";
 
/**
 * POST /api/promotions/applicable
 * Get all applicable automatic promotions for a cart
 */
async function handlePost(
  request: NextRequest
): Promise<NextResponse<ApiSuccessResponse<unknown> | ApiErrorResponse>> {
  const session = await auth();
  let userId: number | undefined;
 
  if (session?.user?.email) {
    const user = await prisma.user.findUnique({
      where: { email: session.user.email },
      select: { id: true }});
    userId = user?.id;
  }
 
  const body = await request.json();
  const { cart } = body;
 
  if (!cart || !Array.isArray(cart) || cart.length === 0) {
    return successResponse({
      promotions: [],
      stackedResult: null});
  }
 
  // Validate cart items structure
  const cartItems: CartItem[] = cart.map((item) => ({
    productId: item.productId,
    quantity: item.quantity,
    price: item.price,
    categoryId: item.categoryId,
    title: item.title}));
 
  // Find applicable promotions
  const applicablePromotions = await promotionEngine.findApplicablePromotions(cartItems, userId);
 
  // Stack promotions to get the best combination
  const stackedResult = promotionEngine.stackPromotions(applicablePromotions, cartItems);
 
  // Format response
  const formattedPromotions = applicablePromotions.map((ap) => ({
    id: ap.promotion.id,
    name: ap.promotion.name,
    displayName: ap.promotion.displayName,
    type: ap.promotion.type,
    discountAmount: ap.discountAmount,
    message: ap.message,
    affectedItems: ap.affectedItems,
    stackable: ap.promotion.stackable}));
 
  return successResponse({
    promotions: formattedPromotions,
    stackedResult: {
      totalDiscount: stackedResult.totalDiscount,
      freeShipping: stackedResult.freeShipping,
      freeItems: stackedResult.freeItems,
      savingsBreakdown: stackedResult.savingsBreakdown,
      appliedPromotions: stackedResult.promotions.map((p) => ({
        id: p.promotion.id,
        name: p.promotion.displayName || p.promotion.name,
        discountAmount: p.discountAmount}))}});
}
 
export const POST = withErrorHandling(handlePost);