All files / bc-mongodb-implementation-demo/src/features/orders order.controller.js

45.45% Statements 20/44
51.72% Branches 15/29
66.66% Functions 2/3
45.45% Lines 20/44

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 1013x 3x 3x 3x         3x         3x 2x     2x 1x         1x 1x                                                                                                                       3x 3x 3x 1x   2x       2x 1x   1x     3x  
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',
    )
  }
 
  Eif (!books || !Array.isArray(books) || books.length === 0) {
    throw new BadRequestError('Order must contain at least one book.')
  }
 
  const session = await mongoose.startSession()
  try {
    session.startTransaction()
 
    const updatedBooksPromises = books.map(async (orderItem) => {
      const book = await Book.findById(orderItem.bookId).session(session)
      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({ session })
    })
 
    await Promise.all(updatedBooksPromises)
 
    const newOrderData = {
      name,
      email,
      phone,
      shippingAddress,
      books,
      status: 'pending',
    }
 
    const newOrder = new Order(newOrderData)
    const savedOrder = await newOrder.save({ session })
 
    await session.commitTransaction()
 
    res.status(StatusCodes.CREATED).json(savedOrder)
  } catch (error) {
    if (session.inTransaction()) {
      await session.abortTransaction()
    }
    if (
      error instanceof BadRequestError ||
      error instanceof NotFoundError ||
      error instanceof UnauthenticatedError
    ) {
      throw error
    }
    throw new Error(`Order creation failed: ${error.message}`)
  } finally {
    if (session) {
      session.endSession()
    }
  }
}
 
// @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 }