All files / features/orders order.controller.js

100% Statements 37/37
100% Branches 25/25
100% Functions 3/3
100% Lines 37/37

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 891x 1x 1x 1x         1x         1x 7x     7x 1x         6x 1x     5x 5x 5x 5x 1x   4x 1x       3x 3x     5x   2x                 2x 2x   1x   4x         2x   2x             1x 3x 3x 1x   2x       2x 1x   1x     1x  
const Order = require('./order.model')
const Book = require('../books/book.model')
const mongoose = require('mongoose')
const { StatusCodes } = require('http-status-codes')
const {
  BadRequestError,
  NotFoundError,
  UnauthenticatedError,
} = require('../../errors')
 
// @desc Create new order
// @route POST /api/v1/orders
// @access Public
const createOrder = async (req, res) => {
  const { name, email, phone, shippingAddress, books } = req.body
 
  // Basic validation
  if (!name || !email || !shippingAddress) {
    throw new BadRequestError(
      'Name, email, shipping address and total price are required',
    )
  }
 
  if (!books || !Array.isArray(books) || books.length === 0) {
    throw new BadRequestError('Order must contain at least one book.')
  }
 
  try {
    const updatedBooksPromises = books.map(async (orderItem) => {
      const book = await Book.findById(orderItem.bookId)
      if (!book) {
        throw new NotFoundError(`Book with id ${orderItem.bookId} not found.`)
      }
      if (book.quantityInStock < orderItem.quantity) {
        throw new BadRequestError(
          `Not enough stock for book: ${book.title}. Available: ${book.quantityInStock}, Requested: ${orderItem.quantity}`,
        )
      }
      book.quantityInStock -= orderItem.quantity
      await book.save()
    })
 
    await Promise.all(updatedBooksPromises)
 
    const newOrderData = {
      name,
      email,
      phone,
      shippingAddress,
      books,
      status: 'pending',
    }
 
    const newOrder = new Order(newOrderData)
    const savedOrder = await newOrder.save()
 
    res.status(StatusCodes.CREATED).json(savedOrder)
  } catch (error) {
    if (
      error instanceof BadRequestError ||
      error instanceof NotFoundError ||
      error instanceof UnauthenticatedError
    ) {
      throw error
    }
    throw new Error(`Order creation failed: ${error.message}`)
  }
}
 
// @desc Get orders by email
// @route GET /api/v1/orders/email/:email
// @access Public // Could be private if only for logged-in users to see their own orders
const getOrderByEmail = async (req, res) => {
  const { email } = req.params
  if (!email) {
    throw new BadRequestError('Email parameter is required')
  }
  const orders = await Order.find({ email })
    .populate('books.bookId', 'title')
    .sort({ createdAt: -1 })
 
  if (!orders || orders.length === 0) {
    throw new NotFoundError(`No orders found for email: ${email}`)
  }
  res.status(StatusCodes.OK).json(orders)
}
 
module.exports = { createOrder, getOrderByEmail }